PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem mit Kontextmenü bzw. Popup-Menü in Qt



Kirsche
28-10-2005, 14:14
Hallo Leute,

ich habe ein Problem beim Benutzen eines Popupmenüs. Es öffnet sich bei einem Rechtsklick, ist also ein Kontextmenü. Das Problem besteht darin, dass ich Häkchen setzen möchte und außerdem noch nicht bekannt ist, wie viele Einträge das Menü haben wird. Das Kontextmenü gehört zu einer Tabelle und soll Tabellenspalten ein- bzw. ausblenden, je nachdem ob das Häkchen gesetzt wird oder nicht. Das Menü "showHideMenu" befindet sich als Unterpunkt im eigentlichen Kontextmenü "contextMenu".

Ich habe zwei Ansätze, die jeweils ein eigenes Problem haben. Außerdem stürzt das Programm anschließend in beiden Fällen ab, statt die Spalten auszublenden.

1. Ansatz: "mit insertItem"

QPopupMenu* showHideMenu = new QPopupMenu( contextMenu );
showHideMenu->setCheckable( true );
QString label;

for( int i = 0; i < table->numCols(); i++ )
{
label = table->horizontalHeader()->label( i );
showHideMenu->insertItem( label, i ,i );
showHideMenu->setItemChecked( i, true );
}
connect( showHideMenu, SIGNAL( activated( int ) ), SLOT( slotShowHideColumn( int ) ) );
contextMenu->insertItem(tr("&Show/Hide Columns"), showHideMenu);

Hier ist das Problem, dass die Häkchen sich nicht umsetzen lassen. Allerdings wird eine gültige Id gesendet.

2. Ansatz:

QPopupMenu* showHideMenu = new QPopupMenu( contextMenu );
QString label;

QAction* showHideAction;
QString label;

for( int i = 0; i < table->numCols(); i++ )
{
label = table->horizontalHeader()->label( i );
showHideAction = new QAction( label, label, showHideMenu );
showHideAction->setToggleAction( true );
showHideAction->setOn( true );
showHideAction->addTo( showHideMenu );
connect( showHideAction, SIGNAL( toggled( bool ) ), showHideAction, SLOT( setOn( bool ) ) );
}
connect( showHideMenu, SIGNAL( activated( int ) ), SLOT( slotShowHideColumn( int ) ) );
contextMenu->insertItem(tr("&Show/Hide Columns"), showHideMenu);

Hier ist das Problem, dass ich keine Id für die Items setzen kann. Dadurch wird immer -69 als Id gesendet. Damit kann ich natürlich nichts anfangen. Dafür wird das Häkchen richtig umgesetzt.

Ich brauche die Id, um die richtige Spalte in der Tabelle ein- oder auszublenden. Ich weiß schließlich vorher nicht, wie viele Spalten die Tabelle haben wird. Ich muss dazu außerdem abtesten, ob das Häkchen gesetzt ist oder nicht.

void MyWidget::slotShowHideColumn( int id )
{
for( int i = 0; i < table->numCols(); i++ )
{
if( showHideMenu->isItemChecked( id ) == true )
{
table->hideColumn( id );
}
else
{
table->showColumn( id );
}
}
}

Dabei stürzt das Programm immer ab, auch wenn eine gültige Id übertragen wurde. Ich habe "showHideMenu" als Membervariable, also müsste sie noch vorhanden sein. Oder wurde das Kontextmenü doch zerstört und ist nun ungültig? Ich führe es mit "exec( pos )" aus. :confused:

Ich wäre auch für jede andere Variante dankbar, um die Spalten ein- und ausblenden zu können.

Vielen Dank,
Kirstin

Kirsche
28-10-2005, 17:45
Hallo Leute,

ich habe es jetzt über einige Umwege hinbekommen. Ich benutze QSignalMapper und speicher die gesetzten Werte in einem Vektor zwischen. Außerdem benutze ich zwei Funktionen hintereinander. Die erste wird durch das Setzen bzw. Entfernen eines Häkchens aktivert und merkt sich, ob gesetzt oder entfernt wurde. Die andere Funktion bekommt über den SignalMapper die Id des Eintrags. Abhängig von dem Wert, der in der ersten Funktion gesetzt wurde, wird die entsprechende Spalte ein- oder ausgeblendet.

Ich gehe davon aus, dass Signale in der Reihenfolge abgearbeitet werden, in der sie auftreten und auch die Reihenfolge der connects eine Rolle spielt. Die beiden Funktionen muss nämlich zwingend nacheinander aufgerufen werden.

Schöne Grüße,

anda_skoa
28-10-2005, 19:43
Wenn mehrere Signals hintereinander ausgesendet werden, werden die jeweiligen Slots auch hintereinander ausgeführt.

Die Slots, die mit dem selben Signal verbunden sind, werden in irgendeiner Reihenfolge ausgeführt.

Die erste Variante sieht ansich gut aus.

Allerdings würde ich nicht jedesmal ein neues Menü erzeugen, sondern nur den Inhalt mit clear() löschen und neu Items einfügen.
Dann braucht man nur einmal die connects auszuführen, etc

in etwas so



void Klasse::contextMenuEvent(QContextMenuEvent* event)
{
if (m_contextMenu == 0) m_contextMenu = new QPopupMenu(this);
if (m_showHideMenu == 0)
{
m_showHideMenu = new QPopupMenu(m_contextMenu);
m_showHideMenu->setCheckable(true);
m_contextMenu->insertItem(tr("&Show/Hide Columns"), m_showHideMenu);
// ... connect von activated(int)
}

m_showHideMenu->clear();

for (.......)
{
m_showHideMenu->insertItem(label, i, i);
}
}


Im Slot dann


if (m_showHideMenu->isItemChecked(i)) // show
else // hide


Ciao,
_