Página 1 de 2
hbqt (again)
Enviado: 05 Dez 2011 11:32
por MARCELOG
Olá pessoal,
continuo estudando a hbqtgui e no processo, criando um pequeno aplicativo.
Optei por criar um menu com base numa tree (qtreewidget).
Conforme a seleção do usuário, a página de uma qstackedwidget relacionada é exibida.
Tudo funcionou sem maiores problemas até a página 6 do qstackedwidget.
Ao criar a página de número 7 num aquivo prg separado e adicioná-lo ao projeto como os demais, tudo ainda funciona certinho.
Todos os procedimentos previsos são normalmente realizados, sem quaisquer erros.
Entretanto, quando fecho o sistema, aparece aquele famigerado aviso de que "O programaX encontrou um problema e precisa ser fechado", indicando o envio de relatório para a Microsoft.
O aviso faz referência ao nome da app e à qtgui4.dll.
Por outro lado, é estranho, já que somente é emitido quando o programa é fechado.
O que poder ser o problema? Tem como solucioná-lo?
Desligar o aviso de erro do Windows para o programa não está entre as opções... (rsrsrsrs)
Obrigado.
MarceloG.
hbqt (again)
Enviado: 05 Dez 2011 12:01
por Pablo César
Pelo que eu sei o QT precisa de algumas bibliotecas que serão utilizadas em run-time. Isto é, precisará sempre carregar com o seu exe os seguintes arquivos: QtCore4.dll, QtGui4.dll, QtNetwork4.dll, QtWebKit4.dll e mingwm10.dll (só não sei se este ultimo destina-se somente ao HMG4. Você também poderá colocar esse aquivos no Windows\system32 (no path do Windows) para não ter que colocar junto em cada sistema. Não estou seguro se são todos esses arquivos, vai colocando um a um a medida que dê erro, pois como eu disse, talvez destina-se para HMG que trabalha com QT agora na versão 4. Maiores informações pode ser obtidas neste tópico:
http://hmgforum.com/viewtopic.php?f=24& ... dll#p16393
hbqt (again)
Enviado: 05 Dez 2011 12:17
por MARCELOG
Olá Pablo,
obrigado por responder.
Mas como eu disse, o sistema funciona normalmente.
Todas as ddl´s necessárias estão presentes.
O único problema é que, ao ser fechado, surge o erro indicado.
Se eu não linkar o último arquivo, tudo funciona legal.
Ao fechado, nesse condição, sem linkar o último aruqivo, o aplicativo não gera qualquer mensagem de erro.
MarceloG
Ps: Vou verificar se houve corrupção de alguma dll.
hbqt (again)
Enviado: 05 Dez 2011 12:43
por Pablo César
Ps: Vou verificar se houve corrupção de alguma dll.
Boa idéia. Mas é esquisito isso.
hbqt (again)
Enviado: 05 Dez 2011 13:45
por Stanis Luksys
Olá,
Normalmente isso ocorre quando você finaliza o programa sem antes matar os objetos.
Para prevenir isso é necessário ter uma função de encerramento EXIT FUNCTION, na qual se atribue valor NIL para os objetos que estão em memória.
Veja também se você está dando um pai para o objeto (sua janela seria o pai), o que pode ser feito através do SetParent().
Se você fizer isso, pode usar um set da Qt, se não me engano, DestroyOnClose, algo assim. Ao fazer isso ele destroi automaticamente todos os filhos da janela quando ela fecha.
Uma outra coisa bastante importante é acabar o programa quando a última janela é fechada, se não me engano é o o QuitOnLastWindowClose.
Não tenho certeza nos nomes dos métodos, e to na correria, não vai dar pra conferir agora, mas da uma olhada no Qt Assistant. A idéia é essa.
Abraços.
hbqt (again)
Enviado: 06 Dez 2011 10:27
por MARCELOG
Olá Stanis,
de novo, obrigado pela atenção.
Mas o negócio é o seguinte:
Estou criando o projeto com base no exemplo do demoqt.prg da pasta tests.
Assim, no prg principal as varáveis para armazenar os objetos foram criadas.
A partir daí, criei a janela principal e o widget central.
Criei um layout vinculado ao widget central e acrescentei à esquerda um treewidget e, à direita, o stackedwidget.
Conforme o treewidget é alterado, a page do stackedwidget é definida.
Para criar as page´s do stackedwidget utilizo uma variável local que recebe de uma função, dentro de uma array, os objetos que a compõem (frames, layouts, labels, lineedits, tables, etc.).
No primeiro argumento, está o widget principal que armazena todos os demais, inclusive os layout´s, e é vinculado ao estackedwidget.
Dessa forma, as variáveis contém os objetos "principais" e os arrays contendo os objetos "secundários" que compõem as pages.
Todos os prg´s que devolvem as arrays têm uma única estrutura, não justificando o aparecimento do erro noticiado em face da inclusão de mais um.
Por outro lado, ao que parece, o erro está acontecendo quando o :exec() é abortado, impedindo a execução das funções posteriores, inclusive a sugerida, que "limpa" a memória.
Exemplo simplificado
no prg principal
...
aPage1:=PAGE1()
stackedwidget:addwidget(aPage[1])
...
function PAGE1()
local a,b,c
a:=qframe()
b:=qvboxlayout(a)
c:=qlabel()
b:addwidget(c)
return {a,b,c}
MarceloG
Ps: os widgets que compõem a stackedwidget, mesmo porque serão adicionados à mesma, s.m.j., não precisam da definição do widget principal, certo?
hbqt (again)
Enviado: 06 Dez 2011 11:12
por Stanis Luksys
Olá,
Avaliando assim rapidamente, acho que o problema pode estar nestas variáveis locais.
Pois veja, você cria o qframe e o qlabel como local, mas não fala quem é o pai deles.
Depois disso o programa sai desta funcao e mata estas variáveis, que eram locais. Os objetos continuam na tela, porém sem referência na memória.
Ao fechar o programa, a própria Qt tenta automaticamente destruir estes objetos, mas como eles não são filhos de ninguém, e não estão diretamente referenciados na memória, da erro.
É só uma hipótese, mude essas vars para pública e coloque um pai para elas através do setparent. Veja se o erro continua.
Se o erro parar, volte essas variáveis para locais, mas arrume um jeito delas serem retornadas para a função que as chamou.
Se sua variável local cria objetos de tela, o normal seria a funcao retornar este objeto, mais ou menos assim:
Código: Selecionar todos
Function CriaFrame( oObjPai ) //oObjPai é a janela ou widget
Local frame := QFrame()
frame:setParent(oObjPai)
// um monte de sets do frame aqui
Return frame
Você pode retornar vários objetos em um array, e depois trabalhar com eles normalmente também. O importante é que eles continuem na memória quando o program sair da função que os criou.
Abraços.
hbqt (again)
Enviado: 06 Dez 2011 11:19
por Stanis Luksys
Opa,
Eu não tinha prestado atenção, mas você já está retornando os objetos em um array, né? Falha nossa.
Olha, eu não costumo trabalhar desta maneira não. o exemplo do qtdemo é horrível.
Eu crio uma classe para a janela a principal e adiciono objetos nela.
Abraços.
hbqt (again)
Enviado: 06 Dez 2011 11:32
por Stanis Luksys
Continuando,
Programar com a Qt não fica bom se não for orientado a objetos.
Sempre que uso a Qt, eu utilizo o recurso de
herança, para criar os meus objetos. Eu tive que vasculhar muito como os caras lá do harbour fizeram essa gambi com a Qt, mas o resultado é muito bom.
Vou dar um exemplo bem rápido de como eu crio uma Janela principal com um grid dentro:
Código: Selecionar todos
CREATE CLASS TMainWindow FROM HB_QMainWindow // Crio uma classe que herda tudo da QMainWindow()
DATA meuGrid //meu grid passa a ser um obj que nada mais é do que uma propriedde da minha janela
METHOD create()
METHOD buildGrid()
ENDCLASS
/* create ***************************/
METHOD TMainWindow:create( )
::setWindowTitle(_APP_NAME)
::setWindowIcon( QIcon(_MEU_ICO) )
::setMouseTracking(.t.)
::setMinimumSize( 500, 530 )
::setMaximumSize( 500, 530 )
::resize( 500, 530 )
::buildGrid() // aqui cria o grid
RETURN SELF
/* buildGrid ***************************/
METHOD TMainWindow:buildGrid()
LOCAL x, y, gridItem
::grid := QTableWidget( 9, 9, SELF )
::grid:move( 25, 50 )
::grid:setEditTriggers(0)
::grid:setFont( ::fontUser )
::grid:verticalHeader:setDefaultSectionSize(50)
::grid:verticalHeader:setMinimumSectionSize(50)
::grid:horizontalHeader:setDefaultSectionSize(50)
::grid:horizontalHeader:setMinimumSectionSize(50)
::grid:setHorizontalScrollBarPolicy(1)
::grid:setVerticalScrollBarPolicy(1)
::grid:verticalHeader:hide()
::grid:horizontalHeader:hide()
::grid:setMinimumSize(454,454)
::grid:setMaximumSize(454,454)
::grid:setFrameStyle(QFrame_NoFrame)
::grid:setStyleSheet("border: 2px solid #000; gridline-color:#000; color:#4040C0; background-color:white; selection-background-color:#69c; selection-color:#fff")
::grid:setSelectionMode(1)
::grid:setContextMenuPolicy(3)
::grid:setMouseTracking(.t.)
::grid:setIconSize(qsize(44,44))
RETURN NIL
Bom, qual a vantagem de trabalhar assim com a herança?
É o seguinte, além de eu ter todos os métodos normais que a janela principal tem por padrão, eu posso adicionar novos métodos, então digamos que estou numa tela de PDV.
Eu posso fazer:
Código: Selecionar todos
JanelaPDV:setMinimumSize( 500, 530 ) // um metodo padrao da qt
JanelaPDV:adicionarItemNoCupom(params) // eu que inventei este metodo
JanelaPDV:exibirMsg(params) // eu que inventei este metodo
Entendeu?
hbqt (again)
Enviado: 06 Dez 2011 13:06
por MARCELOG
Olá pessoal,
obrigado pela dica Stanis, vou estudar os procedimentos.
Todavia, com o método TE (de tentativa e erro), encontrei o problema.
Ao que parece, em algumas situações, o stretch não é corretamente definido para os layouts dentro de layouts, causando o erro.
Assim, desabilitei os mesmos e o programa voltou a funcionar normalmente.
Vou testar outras condições e posto o resultado mais tarde.
Valeu.
MarceloG
hbqt (again)
Enviado: 07 Dez 2011 09:50
por MARCELOG
Olá Stanis,
apesar das alterações efetuadas, o erro persiste.
Deve ser algum bug no objeto que eu pretendo usar, ou seja, o qstackedwidget.
Logo, outra abordagem se faz necessário.
Assim, pretendo deixar um qwidget principal e inserir objetos nele conforme a necessidade, simulando o objeto qstackedwidget.
Para isso preciso saber quais os objetos dentro do mesmo e como "matá-los".
Como você tá fera em hbqt, por acaso sabe como retornar os objetos integrados ao qwidget e matá-los?
O método children e destroy, ao que parece, não foi implementado no qwidget.
Obrigado.
MarceloG
hbqt (again)
Enviado: 07 Dez 2011 12:18
por Stanis Luksys
Olá,
A melhor forma de fazer isso é por herança como eu coloquei mais acima.
Uma vez que eu criei uma classe minha que herda o widget/mainwindow ou seja o que for, eu posso adicionar um método destroy nesta classe e matar todos os objetos filhos apenas fazendo:
Código: Selecionar todos
Procedure Main()
// blabla
janela := TMinhaClasse():create()
janela:show() // metodo herdado da classe original da qt
janela:ficarCorDeRosa() // metodo criado
janela:close() // metodo herdado
janela:destroy() // metodo criado para matar a minha classe
Return
E dentro dela:
Código: Selecionar todos
METHOD TMinhaClasse:destroy()
obj1 := NIL
obj2 := NIL
obj3 := NIL
RETURN NIL
Eu faço assim.
hbqt (again)
Enviado: 10 Dez 2011 13:15
por MARCELOG
Olá Stanis,
o que eu estou fazendo de errado?
Há compilação mas o arquivo não executa.
Obrigado.
MarceloG
Código: Selecionar todos
#INCLUDE 'hbclass.ch'
#INCLUDE 'hbqtgui.ch'
//REQUEST HB_CODEPAGE_PT850
//=======================================================================
PROCEDURE MAIN()
LOCAL x, o
x:=QAPPLICATION()
o:=TxMAIN():NEW()
o:SHOW()
x:EXEC()
RETURN
//=======================================================================
CREATE CLASS TxMAIN FROM HB_QMAINWINDOW
METHOD NEW() // CONSTRUCTOR
ENDCLASS
//=======================================================================
METHOD TxMAIN:NEW()
::SETWINDOWTITLE('cTitulo')
::RESIZE(500,500)
RETURN SELF
hbqt (again)
Enviado: 11 Dez 2011 11:22
por Stanis Luksys
Olá,
Faça o seguinte: altere o nome do seu método new para create, e depois chame assim:
Deve funcionar.
O método new é padrâo, não deve ser sobreposto por um criado por você, senão ele nâo executa as rotinas necessárias para a criaçâo da janela em sí. Se você cria um método new, deve dentro dele fazer tudo que o new automático faz, ou seja todo o código C. Entendeu?
Abraços.
hbqt (again)
Enviado: 13 Dez 2011 11:42
por MARCELOG
Olá Stanis, obrigado!
Entendi os procedimentos.
Nada como um "empurrãozinho" para pegar no tranco.
Vou continuar estudando...
MarceloG