[gelöst] Optimierung Item-Suche im QTreeWidget

Alles rund um die Programmierung mit Qt
Antworten
snowflake
Beiträge: 7
Registriert: 12. August 2010 21:06

[gelöst] Optimierung Item-Suche im QTreeWidget

Beitrag von snowflake »

Guten Morgen,

möchte meinen Einstieg schon gleich mit 2 Problemen feiern ;)

ich benutze QT open source SDK in Version 4.6.3 (Package 2010.04) zusammen mit Eclipse Helios Release und QT Eclipse Integration v1.6.1

dies ist mein Einstieg in ein großes Projekt in c++ und QT, deswegen gibts auch noch ein paar grundlegende Probleme ;)

hab mich schon bißchen in das signal / slot Verhalten eingelesen und jetzt nach knappen 3 Wochen auch schon bißchen was zusammen bekommen, aber manchmal zwickt es noch ;)

also, genug geschwafelt, kommen wir zu den Punkten

ich bilde in einer QGraphicsView Polygone ab, die von der Datenhaltung her gruppiert sein können in Segmente und mehrere Segmente wiederum in Layern.

Nun zeichne ich beim Auslesen meiner Polygone alle in das QGraphicsView, was auch soweit schon funktioniert. Gleichzeitig werden alle Polygone nach oben genannter Hierarchie in das TreeWidget eingefügt, Layer ist TopItem, Segment ist Child von Layer und Polygon Child von Segment. In Spalte 1 steht der Name des Objekts und in Spalte 2 eine Checkbox, mit der ich die Sichtbarkeit der einzelnen toggeln kann (also entweder kompletter Layer, kompl. Segment oder einzelnes Polygon weg)

dazu hab ich die stateChanged Methode überschrieben und such mir hierin wieder mein Objekt, das ausgewählt wurde.

Meine Lösung funktioniert zwar, allerdings scheint es mir immer noch zu kompliziert gedacht. Was meint ihr ?

Layer, Segments und Polygone sind QVector von eigenen Datenklassen, die ich angelegt hab.

Code: Alles auswählen

// react on toggling the visibility checkbox within the treeWidget
void PolyCreater::stateChanged(int signal)
{
	// detect the selected checkbox
	QCheckBox *cb = qobject_cast<QCheckBox *>( sender() );

	// index of the selected layer (either as directly chosen or as parent node
	// of the chosen polygon or segment)
	int selectedLayerIndex = -1;
	// index of the selected segment (either as directly chosen or as parent node
	// of the chosen polygon)
	int selectedSegmentIndex = -1;
	// index of the selected polygon
	int selectedPolygonIndex = -1;

	// item for the selected item of the treewidget
	QTreeWidgetItem *selectedItem;

	// if the checkbox could be detected
	if (cb)
	{
		// choose the selected item
		selectedItem = ui.treeWidget->itemAt(cb->pos());

		// check if the selected item is on top level (which means it is a layer)
		selectedLayerIndex = ui.treeWidget->indexOfTopLevelItem(selectedItem);

		// if it is a layer
		if (-1 != selectedLayerIndex)
		{
			// change the layers visibility
			polyHelper->layers[selectedLayerIndex].isVisible = (signal == Qt::Checked);

			// and repaint the polygons
			paintAllPolygons();
		}
		// otherwise
		else
		{
			// if it is not a layer
			if (-1 == selectedLayerIndex)
			{
				// check if the parent node of the selected item is a layer
				selectedLayerIndex = ui.treeWidget->indexOfTopLevelItem(selectedItem->parent());

				// if the parent node is a layer
				if (-1 != selectedLayerIndex)
				{
					// then search within for the selected child (which means it is a segment)
					selectedSegmentIndex = ui.treeWidget->topLevelItem(selectedLayerIndex)->indexOfChild(selectedItem);

					// if the selected item is a segment
					if (-1 != selectedSegmentIndex)
					{
						// change the segments visibility
						polyHelper->layers[selectedLayerIndex].segments[selectedSegmentIndex].isVisible = (signal == Qt::Checked);

						// and repaint the polygons
						paintAllPolygons();
					}
				}
				// otherwise
				else
				{
					// if the parent node is not a layer (which means the parent node has to be a segment in a 3 subsequent node structure)
					if (-1 == selectedLayerIndex)
					{
						// detect the layer index through the parent of the parent (which means the parent of the selected item is a segment
						// and the parent of the segment is the layer)
						selectedLayerIndex = ui.treeWidget->indexOfTopLevelItem(selectedItem->parent()->parent());

						// detect the segment index within the above selected layer through the parent of selected item (which means the
						// parent is a segment)
						selectedSegmentIndex = ui.treeWidget->topLevelItem(selectedLayerIndex)->indexOfChild(selectedItem->parent());

						// search within the selected layer and segment for the selected polygon
						selectedPolygonIndex = ui.treeWidget->topLevelItem(selectedLayerIndex)->child(selectedSegmentIndex)->indexOfChild(selectedItem);

						// if the polygon could be found (which is the last chance, because the who emitted the stateChanged event was not found
						// within the upper layer and segment childs)
						if (-1 != selectedPolygonIndex)
						{
							// change the polygons visibility
							polyHelper->layers[selectedLayerIndex].segments[selectedSegmentIndex].polygons[selectedPolygonIndex].isVisible = (signal == Qt::Checked);

							// and repaint the polygons
							paintAllPolygons();
						}
					}
				}
			}
		}
	}
}
so, nächste Baustelle hierbei ist, dass ich die QGraphicsView bzw. die darin enthaltene QGraphicsScene passend zu dem Inhalt, den ich reinzeichne der Größe anpassen will, das ganze sollte weich geschehen, momentan funktioniert es bei mir anhand des überschriebenen MouseReleaseEvent mit einem festen Schwellenwert für das SceneRect, was in ziemlichem Gezappel endet, weil die Scene auf einen Schlag riesig wird.

Hier mal noch mein momentaner Ansatz, auch wenn es ziemlich billig ist

Code: Alles auswählen

void myQGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
	QRect maxRect = QRect(-20, -20, 2000, 1500);

	QRect sceneRect = (scene()->sceneRect()).toRect();

	if (maxRect.contains(sceneRect, TRUE))
	{
		fitInView(scene()->sceneRect(), Qt::KeepAspectRatio);
	}
	else
	{
		scene()->setSceneRect(maxRect);
		fitInView(scene()->sceneRect(), Qt::KeepAspectRatio);
	}

	QGraphicsView::mouseReleaseEvent(event);
}
außerdem fehlt mir noch bißchen Umgang mit der QGraphicsView, ich brauch für meine Zwecke noch eine Zoomfunktion (das geht wohl über den MouseWheelHändler, je nach Up / Down dann halt rein- / rauszoomen), außerdem noch zoomen in einen Bereich (Rectangle), den ich vorher mit gehaltener Maus-Taste o.ä. auswähle und vielleicht noch zoomen auf ein Objekt durch Doppelklick darauf, aber die anderen Punkte wären wichtiger :)

danke :)
Zuletzt geändert von snowflake am 25. August 2010 15:42, insgesamt 2-mal geändert.
snowflake
Beiträge: 7
Registriert: 12. August 2010 21:06

Beitrag von snowflake »

niemand nen Tipp für mich ?
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

*) Dein Vortrag vor dem eigentlichen Problem ist zu lange, konzentrier dich doch aufs wesentliche
*) Dein Code ist vor lauter Kommentaren nur unter erheblichem Aufwand erkenn- und nachvollziehbar. Das tut sich keiner an.

Darum wohl auch keine Antwort. Nächstes Mal drauf achten.

Zu den Problemen:
1) QTreeWidget::itemChanged()-SIGNAL ist doch sooo schön, warum willst du das nicht nutzen? Das wird auch ausgelöst, wenn sich der checkState ändert.
2) setSceneRect() ist nie gut, wenn man nicht weiß was man tut. Sobald du das setzt, musst du dich um die Anpassung des sceneRect selber kümmern. Wenn Items verschoben werden, neue dazukommen, usw. musst du das anpassen, damit nicht Items plötzlich aus dem Sichtbarkeitsbereich verschwinden.
Warum dann eigentlich im mouseReleaseEvent? platzier doch einen Button zum Einpassen.
Ich versteh den Sinn dahinter nicht so ganz... Warum diesen "Schwellenwert"?
3) Zoomen sollte doch echt nicht so schwer sein... Wenn du es über das Mausrad machen willst, brauchst du das wheelEvent.
snowflake
Beiträge: 7
Registriert: 12. August 2010 21:06

Beitrag von snowflake »

ich hab mich eigentlich aufs wesentliche konzentriert ;)

ok, die 1-2 Zeilen mit dem QT-Einstieg hätte ich mir sparen können, aber die Funktionsweisenbeschreibung meiner TreeWidget Items war meiner Meinung nach notwendig, um dann nachvollziehen zu können, ob das Suchen innerhalb des Trees effizient ist.

Habe solche Tuning Fragen schon öfter mal in Coding-Foren gesehen, die waren dann zumeist auch ein bißchen länger ;)

Aber nun gut, das Suchen in dieser Funktion wird ja eh pro Klick immer nur 1 mal ausgeführt und ist dann in paar Millisekunden fertig, dann bleibts eben so :)

trotzdem danke für deine Hilfe, das checkState war das erste funktionierende signal, das ich gefunden hab.

Das Scene Rect wird angepasst, da meine Grafikobjekte bis zu 4000 * 3000 Pixel haben und ich das im Bildschirm einfassen wollte, aber wenn mir hier die View schon weiterhilft, schmeiß ich meine setSceneRect() Aufrufe natürlich wieder raus

Das mouseReleaseEvent war drin, weil ich die Objekte noch beweglich hatte, aber da das wahrscheinlich nicht gebraucht wird, werd ich es wohl auf einen Button setzen :)
Antworten