QPopupMenu, wenn rechte Maustaste und ListViewItem gewählt

Alles rund um die Programmierung mit Qt
Antworten
Notwist
Beiträge: 85
Registriert: 2. März 2005 14:24

QPopupMenu, wenn rechte Maustaste und ListViewItem gewählt

Beitrag von Notwist »

Hallo Leute,

ich hoffe, das nervt nicht, aber es ist nicht so, dass ich erst frage und es dann selbst versuche, sondern wirklich nur, wenn ich nichts gefunden habe, was mir weiterhilft.

Folgendes Problem:

Ich möchte, nachdem ich nun Einträge in meine ListViews gemacht habe, diese Einträge mit der rechten Maustaste anwählen, worauf ein PopupMenu erscheint. Dieses soll je nach Vollständigkeit der ListViewItems (wieviel Untereinträge) diverse Funktionen darüber aufrufbar machen. Ich habe es auch hinbekommen, einfache Popups mit rechter Maustaste zu kreieren, leider erscheinen diese aber nur, wenn ich oben auf die Menuleiste rechts klicke, nicht aber irgendwo im Fenster, was ja der erste Schritt dazu wäre, dass über die ListViewItems über eine if-Anweisung mit currentItem!=0 abzufragen oder so. Hier der Code, der für die Menu-Leiste geht:

Code: Alles auswählen

void KonfiguratorMainWindowImpl::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == RightButton)
	{
		QPopupMenu *contextMenu = new QPopupMenu(this);
		Q_CHECK_PTR( contextMenu );		
		contextMenu->insertItem("Add Identifier", this, SLOT(slot_newEntry()), tr("Ctrl+E"));
		contextMenu->exec(event->globalPos());
		delete contextMenu;	
	}
}
Habe mal irgendetwas über EventFilter gehört, aber peile diese Dinger überhaupt nicht bzw. die bewirken doch eher, dass ich sagen kann, reagiere DU jetzt NICHT auf dieses Event, aber ich kann nciht sagen, ListView reagiere DU aber JETZT AUCH darauf, oder?
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Das Tutorial solltest Du die mal anschauen http://doc.trolltech.com/3.3/tutorial.html
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Notwist
Beiträge: 85
Registriert: 2. März 2005 14:24

Beitrag von Notwist »

Ich habe schon ein paar Tutorials gemacht und dieses hatte ich mir auch schon angeschauen, wenn auch nicht explizit nachgemacht. Aber danke für den Tipp, auch wenn sich das ein wenig angehört hat nach "Frag nicht immer, mach erstmal nen Tutorial, Du Depp!" ;-)

Hab das mit dem rechten MausButton hinbekommen. Poste den Code vielleicht nochmal für Leute, die dasselbe Problem irgendwann mal haben, damit der Thread nicht umsonst ist:

Code: Alles auswählen

void KonfiguratorMainWindowImpl::popupMenuSlot()
{
	if (outputListView->isSelected(outputListView->currentItem())) 
		popupMenuOutput();
}

void KonfiguratorMainWindowImpl::popupMenuOutput()
{
	initPopupMenu();
	contextMenu->insertItem(*addIdent, "Add Identifier", this, SLOT(slot_newEntry()), tr("Ctrl+E"));
	contextMenu->insertItem(*addDataField, "Add DataField",this, SLOT(addDataFieldSlot()));
	contextMenu->insertSeparator();
	contextMenu->insertItem(*erase, "Remove",this, SLOT(slot_eraseListViewItem()), tr("DEL"));
	if (outputListView->currentItem()!=0)
		contextMenu->exec(QCursor::pos());
	delete contextMenu;	
}

void KonfiguratorMainWindowImpl::initPopupMenu()
{
	contextMenu = new QPopupMenu();	
	erase = new QIconSet(QPixmap("icons\\designer_editdelete.png"));
	addIdent = new QIconSet(QPixmap("icons\\designer_filenew.png"));
	addDataField = new QIconSet(QPixmap("icons\\designer_ordertool.png"));
}
Die Einträge in der Header-Datei fehlen hier natürlich noch, zB.:

Code: Alles auswählen

QPopupMenu *contextMenu;
QIconSet *erase, *addIdent, *addDataField; 
Ich weiss nicht, ob das mit der initPopupMenu-Methode besser oder schlechter ist, als das immer in die popupMenuOutput reinzuschreiben. Habe ja mehrere ListViews und müsste den Code dann immer in die einzelnen Methoden reinschreiben, so nur einmal.

Achja: Ausgelöst wird das Ganze über ne Connection, wenn ein ListViewItem mit rechter Maustaste das Signal clicked() bekommt.

Gruß, Notwist
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Notwist hat geschrieben:Ich habe schon ein paar Tutorials gemacht und dieses hatte ich mir auch schon angeschauen, wenn auch nicht explizit nachgemacht. Aber danke für den Tipp, auch wenn sich das ein wenig angehört hat nach "Frag nicht immer, mach erstmal nen Tutorial, Du Depp!" ;-)
Nein, so war das nicht gemeint. Nur postest Du manchmal etwas zu wenig Code und dein Code ist manchmal mhhh gewöhnungsbedürftig ;-)

z.B. würde ich innerhalb von popupMenuOutput() nie ein 'new' machen ud später wieder alles löschen. Besser ist es, das im Konstruktur von KonfiguratorMainWindowImpl zu machen und dann dort nur ein show() oder hide() zu machen. Sonst wird bei jedem Aufruf ein PopupMenu und 3 IconSets erzeugt. Wobei sie sogar verloren gehen (du erzeugst bei jedem Aufruf neue und löschst die alten nicht).
Das PopupMenu würde ich ausserdem nicht mit new erzeugen. Ein einfaches

Code: Alles auswählen

class KonfiguratorMainWindowImpl : public QWasAuchImmer
{
   ...
 private:  
   QPopupMenu m_popup;
   QIconSet m_erase;
   QIconSet m_addIdent;
   QIconSet m_addDataField;
   ...
}

bzw. 

KonfiguratorMainWindowImpl::KonfiguratorMainWindowImpl ()
{
   ...
   m_erase.setPixmap( ... );
   m_addIdent.setPixmap( ... );
   m_addDataField.setPixmap( ... );
}
ist m.E. die bessere Lösung, da Du dich so z.B. nicht um das Löschen der Objekte kümmern musst (geschieht automatisch in ~KonfiguratorMainWindowImpl).
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Notwist
Beiträge: 85
Registriert: 2. März 2005 14:24

Beitrag von Notwist »

Das mit dem setPixmap(...) ist natürlich sehr viel schöner. Ich habe Deine Lösung mal ausprobiert und sie funktioniert soweit. Das Problem, dass ich hatte, dass ich jedes Mal, wenn ich die rechte Maustaste betätigte, einen zusätzlichen Eintrag in mein Popup bekam, was ich ja vorher über

Code: Alles auswählen

delete contextMenu;
verhindert habe, löst sich nun ja über den Aufruf im Konstruktor.

Das mit show() & hide() im Konstruktor habe ich nicht verstanden. Muss man nicht für jedes neues Fenster-Objekt (also jeder neuen Klasse, die ein Fenster darstellt) ein show() aufrufen?

Wann würdest Du generell ein Objekt mit

Code: Alles auswählen

QPopupMenu popup = new QPopupMenu();
und wann mit

Code: Alles auswählen

QPopupMenu popup;
erschaffen? New allokiert ja einen festen Speicherplatz. Was passiert denn genau ohne das new (ich habe noch sehr viele Verständnis-Lücken in C++)?

Und nochmal zum Programmierstil. Du setzt ein m_ vor die Variablen, wenn sie in der Klasse private sind oder wie machst Du das? Habe noch nie so große Projekte bearbeitet, da ging das bis jetzt immer ohne, aber ich will mir ja einen besseren Stil angewöhnen. Du scheinst da sehr viel erfahrener zu sein. Was für Vor- und Nachteile hat das alles? Klar, man muss nicht immer in die Header-Datei schauen, um zu sehen, wie die Variablen deklariert sind.

Gruß, Notwist
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Notwist hat geschrieben: Das mit show() & hide() im Konstruktor habe ich nicht verstanden. Muss man nicht für jedes neues Fenster-Objekt (also jeder neuen Klasse, die ein Fenster darstellt) ein show() aufrufen?
nein, damit meinte ich das Popup. Allerdings geht das ja von allein wieder weg und anzeigen kann man es mit exec(). Hätte wohl doch erstmal die Doku lesen sollen ;)
Notwist hat geschrieben: Wann würdest Du generell ein Objekt mit

Code: Alles auswählen

QPopupMenu popup = new QPopupMenu();
und wann mit

Code: Alles auswählen

QPopupMenu popup;
erschaffen? New allokiert ja einen festen Speicherplatz. Was passiert denn genau ohne das new (ich habe noch sehr viele Verständnis-Lücken in C++)?
Ich bin eigentlich eher für die 'statische' Variante, also ohne new. Da muss man sich nämlich nicht um das Löschen zu kümmern :)
Sobald du ein Objekt innerhalb einer Klasse verwendest würde ich immer ohne Pointer arbeiten. Das Objekt wird automatisch im Konstruktur der Klasse, in der Du das Objekt definiert hast, aufgerufen. Es passiert im Grunde das:

Code: Alles auswählen

MyWidget::MyWidget( QWidget *parent ) : myPopup()
Hat eine Klasse keinen Standardkonstruktor, sondern braucht mind. eine Variable, musst Du dies selbst erledigen:

Code: Alles auswählen

MyWidget::MyWidget( QWidget *parent ) : myPopup( 5 )
Notwist hat geschrieben: Und nochmal zum Programmierstil. Du setzt ein m_ vor die Variablen, wenn sie in der Klasse private sind oder wie machst Du das?
Dabei geht es eigentlich nur darum, möglichst schnell ohne grosses Nachschauen zu wissen, was das für eine Variable ist. Mit einer Variablenezeichnung a'la 'popup' kann man das nicht so ohne weiteres rausfinden. Heisst es dagegen m_popup weiss man zumindest schon mal, dass die Variable zu der Klasse gehört (egal ob private, protected oder public). Ein m_cPopup würde mir evtl. sogar sagen, dass dies ein Object ist und nicht ein int ( m_iPopup ) oder ein char-String ( m_szPopup ). Dies nennt man ungarische Notation. Wobei ich für Ints eben i anstatt n verwende :)
Notwist hat geschrieben: Habe noch nie so große Projekte bearbeitet, da ging das bis jetzt immer ohne, aber ich will mir ja einen besseren Stil angewöhnen. Du scheinst da sehr viel erfahrener zu sein. Was für Vor- und Nachteile hat das alles? Klar, man muss nicht immer in die Header-Datei schauen, um zu sehen, wie die Variablen deklariert sind.
Ausserdem benutze ich noch astyle mit den Parametern 'astyle -slP --convert-tabs'. Es macht imo den Code sehr viel lesbarer. Bei mir muss astyle kaum mehr was ändern so sehr habe ich mir den Stil angewöhnt.
Der Nachteil davon ist, dass sobald Du in einem anderen Projekt arbeitest, welches nicht von dir ist ( sei es privat oder auf Arbeit), es unter Garantie andere Stilfestlegungen gibt und Du dich anpassen musst.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Antworten