Definindo ToolTip para menus e itens de menus



  • Bem como tive um certo trabalhinho para conseguir, resolvi compartilhar. Se vc tem vontade de setar um ToolTip para um menu ou item de menu (QAction) mas não consegue pq por padrão Qt não exibe ToolTip definido para menus, aqui vai a dica.
    É preciso reescrever a classe QMenu, ou seja, criar um classe que derive de QMenu e interceptar o evento de ToolTip

    .h

    @#ifndef MODQMENU_H
    #define MODQMENU_H

    #include <QMenu>

    class ModQMenu : public QMenu
    {

    public:
    ModQMenu(QString title, QWidget *parent = 0);
    virtual bool event(QEvent *);

    };

    #endif // MODQMENU_H
    @

    .cpp

    @#include "ModQMenu.h"
    #include <QHelpEvent>
    #include <QToolTip>
    #include <iostream>

    ModQMenu::ModQMenu(QString title, QWidget *parent) : QMenu(title, parent)
    {

    }

    bool ModQMenu::event(QEvent *evt)
    {
    const QHelpEvent *helpevt = static_cast<QHelpEvent *>(evt); // Cria uma cópia modificada para QHelpEvent

    if(helpevt->type() == QEvent::ToolTip)          // Testa se o evento disparado foi um ToolTip
    {
        QAction *act = actionAt(helpevt->pos());    // Obtem o QAction que está sobe o foco do mouse
    
        if(act->toolTip() != act->text())    // Testa para ver se foi definido um ToolTip para o action *p.s
            QToolTip::showText(helpevt->globalPos(), act->toolTip(), this);     // Exibe o ToolTip
    
    }
    
    return QMenu::event(evt);
    

    }

    /* p.s Por default o tooltip de um QAction é o seu nome de exibição (nome visivel ao usuário) */ @

    Espero que sirva para futuros buscantes



  • Bem, ontem postei uma dica de como usar ToolTips em menus, reescrevendo a classe QMenu. "ModQMenu":http://developer.qt.nokia.com/forums/viewthread/7225/

    Estou com um problema de travamento da aplicação quando uso a solução QMenu modificada (ModQMenu), quando faço uso dela para criar os menus, a app trava junto com todo o SO. Quando uso QMenu padrão roda direitinho.

    Será vazamento de memória?



  • Legal a iniciativa de compartilhar a solução :-)

    Para fins históricos, segue a "thread original":http://developer.qt.nokia.com/forums/viewthread/7150/ (em inglês) onde há também o procedimento para QMenuBar.



  • Pois é anselmo, só que infelizmente estou tendo problemas com ela, quando usa essa solução para criar os menus, a aplicação trava e junto com ela todo o sistema operacional, só retornando com reset na máquina. Acabei de abrir um tópico sobre esse problema.



  • Para travar o sistema inteiro deve ser algo mais sério e como você disse que com QMenu padrão o problema não acontece, pode ser algum passo da sua reimplementação.

    Qual SO você usa? Aqui (Linux) eu tentaria achar o problema utilizando ferramentas como valgrind, gdb.

    Para tentar reproduzir o erro aqui, você usou ModQMenu junto com o código que postou "nessa thread":http://developer.qt.nokia.com/forums/viewthread/7150/?



  • "Respondido":http://developer.qt.nokia.com/forums/viewthread/7240/

    (/me pensando se não seria o caso de unir os 2 tópicos...)

    EDIT: link acima apontava para o tópico que foi unido a este.



  • Tb uso linux aqui, opensuse

    Não! Estou usando em um código com mais menus, Estou usando o ModQMenu para todos os menus.

    @#ifndef WINDOWMAIN_H
    #define WINDOWMAIN_H

    #include <QMainWindow>
    #include <QMdiArea>
    #include <QList>
    #include "ModQMenu.h"

    class WindowMain : public QMainWindow
    {
    Q_OBJECT

    public:
        WindowMain(QWidget *parent = 0);
    
        ~WindowMain();
    
    private:
    
        QList <QAction *> listarquivos, listredunt, listconfig, listfiscal, listajuda, listrelatori,
                listrelgerenci, listmoviment, listferrament;
    
        // Area MDI
        QMdiArea *mdiarea;
    
        // Menus
        ModQMenu *arquivos;
        ModQMenu *relatorios;
        ModQMenu *ferramentas;
        ModQMenu *fiscal;
        ModQMenu *moviment;
        ModQMenu *configura;
        ModQMenu *ajuda;
        ModQMenu *redundantes;
        ModQMenu *relgerencias;
    
        // QActions de menus
        QAction *clientes;
        QAction *produtos;
        QAction *forneced;
        QAction *represen;
        QAction *usuarios;
        QAction *medicos;
        QAction *sair;
        QAction *enderecos;
        QAction *marclente;
        QAction *matelente;
        QAction *tipopgto;
        QAction *tipolente;
        QAction *tratament;
        QAction *restricoes;
        QAction *autobackup;
        QAction *bdconexao;
        QAction *impressdoc;
        QAction *leiturax;
        QAction *reducaoz;
        QAction *configicms;
        QAction *manual;
        QAction *queisso;
        QAction *sobre;
        QAction *relvenda;
        QAction *relcaixa;
        QAction *relespelhos;
        QAction *relos;
        QAction *partmedica;
        QAction *partfuncio;
        QAction *fatumensal;
        QAction *fatudiario;
        QAction *ranklentes;
        QAction *rankfornec;
        QAction *orcamentos;
        QAction *devolucoes;
        QAction *movicaixa;
        QAction *ordemservic;
        QAction *vendas;
        QAction *contapagar;
        QAction *contarecebe;
        QAction *calcula;
        QAction *callenbord;
        QAction *compatarmlen;
        QAction *backup;
    
        void creatQMenus();
        void creatQActions();
    

    private slots:
    void evoqueSubWind();

    };

    #endif // WINDOWMAIN_H
    @



  • Estou postando o código da aplicação, ainda está crua mesmo

    @#include <QApplication>
    #include <QTextCodec>
    #include <QDesktopWidget>
    #include <QRect>
    #include <QMenuBar>
    #include <QToolBar>
    #include <QStatusBar>

    #include "WindowMain.h"

    WindowMain::WindowMain(QWidget *parent):QMainWindow(parent)
    {
    creatQActions();
    creatQMenus();
    }

    void WindowMain::creatQActions()
    {
    clientes = new QAction(QIcon(":/icoclientes"), "Clientes", this);
    connect(clientes, SIGNAL(triggered()), this, SLOT(evoqueSubWind()));
    listarquivos << clientes;

    produtos = new QAction(QIcon(":/icoprodutos"), "Produtos", this);
    listarquivos << produtos;
    
    forneced = new QAction("Fornecedores", this);
    listarquivos << forneced;
    
    represen = new QAction("Representantes", this);
    listarquivos << represen;
    
    usuarios = new QAction("Usuários", this);
    listarquivos << usuarios;
    
    medicos = new QAction("Médicos", this);
    listarquivos << medicos;
    
    sair = new QAction(QIcon(":/icosair"), "Sair", this);
    sair->setShortcut(tr("CTRL+S"));
    connect(sair,SIGNAL(triggered()), qApp, SLOT(quit()));
    
    enderecos = new QAction("Endereços", this);
    listredunt << enderecos;
    
    marclente = new QAction("Marcas de Lente", this);
    listredunt << marclente;
    
    matelente = new QAction("Metariais de Lente", this);
    listredunt << matelente;
    
    tipopgto = new QAction("Tipos de Pagamento",this);
    listredunt << tipopgto;
    
    tipolente = new QAction("Tipos de Lente", this);
    listredunt << tipolente;
    
    tratament = new QAction("Tratamentos", this);
    listredunt << tratament;
    
    restricoes = new QAction(QIcon(":/icorestricoes"), "Restrinções", this);
    restricoes->setToolTip("Configura o acesso dos usuários ao sistema");
    listconfig << restricoes;
    
    autobackup = new QAction(QIcon(":/icoautoback"), "Backup Automático", this);
    autobackup->setToolTip("Configura o backup automático do sistema");
    listconfig << autobackup;
    
    bdconexao = new QAction(QIcon(":/icoconecbd"), "Conexão com o BD", this);
    bdconexao->setToolTip("Configura a conexão com o banco de dados");
    listconfig << bdconexao;
    
    impressdoc = new QAction("Impressão de Documentos", this);
    impressdoc->setToolTip("Define quais documentos terão impressão automática");
    listconfig << impressdoc;
    
    leiturax = new QAction("Leitura &X", this);
    listfiscal << leiturax;
    
    reducaoz = new QAction("Redução &Z", this);
    listfiscal << reducaoz;
    
    configicms = new QAction("Configurar &ICMS", this);
    listfiscal << configicms;
    
    manual = new QAction(QIcon(":/icomanual"),"Manual", this);
    listajuda << manual;
    
    queisso = new QAction("O que é isso?", this);
    listajuda << queisso;
    
    sobre = new QAction("Sobre o QtOpitca", this);
    listajuda << sobre;
    
    relvenda = new QAction("Relatório de Vendas", this);
    listrelatori << relvenda;
    
    relcaixa = new QAction("Relatório de Caixa", this);
    listrelatori << relcaixa;
    
    relespelhos = new QAction("Relatórios de Espelhos", this);
    listrelatori << relespelhos;
    
    relos = new QAction("Relatório de OS's", this);
    listrelatori << relos;
    
    ranklentes = new QAction("Ranking de Lentes", this);
    listrelatori << ranklentes;
    
    rankfornec = new QAction("Ranking de Fornecedores", this);
    listrelatori << rankfornec;
    
    fatumensal = new QAction("Faturameto Mensal", this);
    listrelgerenci << fatumensal;
    
    fatudiario = new QAction("Faturamento Diário", this);
    listrelgerenci << fatudiario;
    
    partmedica = new QAction("Participação Médica", this);
    listrelgerenci << partmedica;
    
    partfuncio = new QAction("Participação de Funcionários", this);
    listrelgerenci << partfuncio;
    
    orcamentos = new QAction(QIcon(":/icoorcament"), "Orçamentos", this);
    listmoviment << orcamentos;
    
    devolucoes = new QAction(QIcon(":/icodevoluc"), "Devoluções", this);
    listmoviment << devolucoes;
    
    ordemservic = new QAction(QIcon(":/icoos"), "Ordens de Serviço", this);
    listmoviment << ordemservic;
    
    vendas = new QAction(QIcon(":/icovendas"), "Vendas", this);
    listmoviment << vendas;
    
    movicaixa = new QAction("Movimento do Caixa", this);
    listmoviment << movicaixa;
    
    contapagar = new QAction(QIcon(":/icocontaspg"), "Contas a Pagar", this);
    listmoviment << contapagar;
    
    contarecebe = new QAction(QIcon(":/icocontasrc"), "Contas a Receber", this);
    listmoviment << contarecebe;
    
    calcula = new QAction(QIcon(":/icocalculator"), "Calculadora", this);
    listferrament << calcula;
    
    backup = new QAction(QIcon(":/icobackup"), "Backup", this);
    listferrament << backup;
    
    callenbord = new QAction("Calcular borda de lentes", this);
    listferrament << callenbord;
    
    compatarmlen = new QAction("Compatibilidade LENTE x ARMAÇÂO", this);
    listferrament << compatarmlen;
    

    }@



  • Cont......

    @void WindowMain::creatQMenus()
    {

    redundantes = new ModQMenu("Redundantes", this);
    redundantes->addActions(listredunt);
    
    arquivos = new ModQMenu("&Arquivos", this);
    menuBar()->addMenu(arquivos);
    arquivos->addActions(listarquivos);
    arquivos->addSeparator();
    arquivos->addMenu(redundantes);
    arquivos->addSeparator();
    arquivos->addAction(sair);
    
    moviment = new ModQMenu("&Movimentação", this);
    menuBar()->addMenu(moviment);
    moviment->addActions(listmoviment);
    
    ferramentas = new ModQMenu("&Ferramentas", this);
    menuBar()->addMenu(ferramentas);
    ferramentas->addActions(listferrament);
    
    fiscal = new ModQMenu("Fisca&l", this);
    menuBar()->addMenu(fiscal);
    fiscal->addActions(listfiscal);
    
    relgerencias = new ModQMenu("Relatórios Gerenciais", this);
    relgerencias->addActions(listrelgerenci);
    
    relatorios = new ModQMenu("&Relatórios", this);
    menuBar()->addMenu(relatorios);
    relatorios->addActions(listrelatori);
    relatorios->addSeparator();
    relatorios->addMenu(relgerencias);
    
    configura = new ModQMenu("&Configurações", this);
    configura->addActions(listconfig);
    menuBar()->addMenu(configura);
    
    ajuda = new ModQMenu("A&juda", this);
    menuBar()->addMenu(ajuda);
    ajuda->addActions(listajuda);
    

    }

    void WindowMain::evoqueSubWind()
    {
    }

    WindowMain::~WindowMain()
    {
    delete mdiarea;
    }
    @



  • hehe pode ser, se tiver como vc fazer pode unir



  • [quote author="matheusssilva_BR" date="1309267199"]
    Não! Estou usando em um código com mais menus, Estou usando o ModQMenu para todos os menus.
    [/quote]

    Para você não precisar por o código inteiro da sua aplicação aqui, talvez seja mais fácil fazer o seguinte: criar um exemplo menor, usando suas classes de menu e que consiga reprodizir o problema.



  • Resolvi tb postar o código inteiro pois acredito que fazendo um teste com apenas 1 ou 2 menus o problema não aparece, pois logo começo eu testei com apenas 3 menus e funcionou perfeitamente, depois que eu passei a usar em todos os menus da app, foi que começou a apresentar esse problema.

    Talvez eu teria que criar a mesma quantidade de menus para o problema poder aparecer.



  • Acabei de testar apenas no menu 'configura', normal, normal. Mas se eu usar em todos os menus ai dá pau. Isso ta cheirando a sobrecarga de memória, será que não ?



  • OK, aqui dá segmentation fault.

    Uma forma de reproduzir o problema: Abra um menu ("Arquivo", por exemplo), deixe-o aberto e mova o mouse para fora dele. Deixe o mouse imóvel por alguns instantes, ou seja, gere um evento de tooltip e.... crash.

    Esse dá pra reproduzir com apenas 1 menu. O que acontece quando você tem mais menus é que fica mais fácil reproduzir, embora não saiba exatamente como.

    Se você rodar num debugger, verá logo de cara que ao fazer o que descrevi acima você terá o ponteiro act nulo, o que quebra seu

    @
    if(act->toolTip() != act->text()))
    @

    Mudar para

    @
    if(act&&(act->toolTip() != act->text()))
    @

    resolve esse problema. Ainda não consegui reproduzir outros casos em que seu código dá crash, quem sabe mais tarde.



  • ummm analisando agora fica óbvio helpevt->pos() retorna a posição do mouse se actionAt() receber uma posição que não tenha nenhum QAction nela ele vai retornar Null. Eu tentei usar o debugger do Qt Creator, mas fica impossivel analisar pq aqui o sistema todo para, tendo que dar reset na máquina para voltar.

    Vc disse que além desse caso ainda tem outros que gera null pointer ?

    p.s Saudades do Java nessa hora em... Em java ele dispararia uma exceção null pointer exception e me indicaria a linha que estava gerando. :-) , mas.... é c++ então vamos nessa...



  • [quote author="matheusssilva_BR" date="1309284041"]
    Mas o que está retornando nulo é act->toolTip() ou act->text() ?
    [/quote]

    act chega nulo nesse if. O passo anterior está retornando nulo nesse cenário identificado.
    O segmentation fault acontece quando da tentativa de chamar os métodos text() e toolTip() de um objeto que não está lá.

    [quote author="matheusssilva_BR" date="1309284041"]
    O que if(act) testa?
    Testa se o ponteiro é nulo?
    [/quote]

    Sim. Equivale a fazer if (act != 0).

    [quote author="matheusssilva_BR" date="1309284041"]ummm, eu tentei usar o debugger do Qt Creator, mas fica impossivel analisar pq aqui o sistema todo para, tendo que dar reset na máquina para voltar.
    [/quote]

    Bom, pode ser pouca RAM... foi exatamente o que eu fiz aqui (e olha que os 2GB de RAM que tenho aqui já não é tanta coisa hj em dia) :-P

    [quote author="matheusssilva_BR" date="1309284041"]
    Vc disse que além desse caso ainda tem outros que gera null pointer ?
    [/quote]

    Disse que consegui identificar como reproduzir 1 dos casos, se tem mais precisa procurar ;)



  • Desculpe por remover as perguntas mas é que estudando o código consegui as respostas.

    Bem pouca RAM não é, tenho 4 giga DDR3, não sei pq então.

    Bem eu só tinha identificado esse erro até o momento.

    Meu debugger tb não ta legal quando rodo em debugger gera um warning na saída

    warning: GDB: Failed to Set terminal de controle: Argumento inv \ 303 \ 241lido \ n


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.