QGV - CenterOn - Stack overflow, keine Scrollbarbewegung

Alles rund um die Programmierung mit Qt
Antworten
Eric.E
Beiträge: 16
Registriert: 10. November 2011 11:06

QGV - CenterOn - Stack overflow, keine Scrollbarbewegung

Beitrag von Eric.E »

Hallo zusammen.

Mein erster Beitrag und das nach nur wenigen Tagen Qt-Programmierung. Ich versuche mich kurz zu halten
und möglichst korrekt das Problem zu beschreiben.

Der Grundlegende Aufbau sieht wie folgt aus.

Mainwindow -> QGraphicsView -> QGraphicsScene.
In der QGS werden CAD-Zeichnungen, PDFs, Tiffs etc dargestellt. CAD-Zeichnungen mit OpenGl Unterstützung.
Implementiert ist in der QGV ein Zoom über das Mausrad und DragMode per Linksklick.

Anforderung: Bei Klick auf einen Button muss Zoom über Rubberband (Linksklick) und gleichzeitiges Verschieben über Rechtsklick möglich sein.
Um nicht die QMouseEvents überschreiben zu müssen habe ich eine QGV in meine QGS gelegt.
QGraphicsScene->addWidget(QGraphicsView);
Die QGraphicsView ist transparent. Nur drüberlegen geht leider nicht, das sonst die OpenGl Darstellung nicht möglich ist und ich nur eine weiße QGS sehe.
Wenn der Button wieder geklickt wird, wird die QGV ~QGV() gelöscht.

Der Zoom über Rechtecht(Rubberband) funktioniert.

Zum Problem:
Ich habe die 3 Standard-MouseEvents (Press,Move,Release). Bei Rechtsklick wird eine gesonderte Behandlung ausgeführt.
Die MouseEvents werden ausgeührt, aber es bewegen sich keine Scrollbars,... Ich habe bereits mit dem Debugger überprüft ob
Variablenwerte etc stimmen. Alles in Ordnung. Ohne Debugger bekomme ich von MSVC 08 nach ein paar Sekundenbruchteilen folgende Fehlermeldung:
Eine Ausnahme (erste Chance) bei 0x7c920698 in "Programmname".exe: 0xC00000FD: Stack overflow.

Kann mir jemand weiterhelfen?

Code:
void TransparenteQGraphicsView::mousePressEvent(QMouseEvent* event)

Code: Alles auswählen

...
if (event->button() == Qt::RightButton) {	
			LastPanPoint = event->pos();
			setCursor(Qt::ClosedHandCursor); 
			rechtsklick = true;
		}

...
void TransparenteQGraphicsView::mouseMoveEvent(QMouseEvent* event)

Code: Alles auswählen

	if(!LastPanPoint.isNull())
	{
               if (rechtsklick == true)
		{
		  p_centerF = ptr_Parent->mapToScene(ptr_Parent->viewport()->rect().center()) ;
		  delta = mapToScene(LastPanPoint) - mapToScene(event->pos());
		  LastPanPoint = event->pos();
		  ptr_Parent->SetCenter(p_centerF + delta);
		}						
    }
void TransparenteQGraphicsView::mouseReleaseEvent(QMouseEvent *event)

Code: Alles auswählen

...
else if ( event->button() == Qt::RightButton)
	{

		setCursor(Qt::CrossCursor);
		LastPanPoint = QPoint();
		rechtsklick = false;
	}
                event->accept();
...
Die SetCenter liegt in der QGV des MainWindows also nicht in der Transparenten (natürlich):

void QGraphicsView::SetCenter(const QPointF& centerPoint)

Code: Alles auswählen

QRectF visibleArea = mapToScene(rect()).boundingRect();
 
    //Get the scene area
    QRectF sceneBounds = sceneRect();
 
    double boundX = visibleArea.width() / 2.0;
    double boundY = visibleArea.height() / 2.0;
    double boundWidth = sceneBounds.width() - 2.0 * boundX;
    double boundHeight = sceneBounds.height() - 2.0 * boundY;
 
    //The max boundary that the centerPoint can be to
    QRectF bounds(boundX, boundY, boundWidth, boundHeight);
 
    if(bounds.contains(centerPoint)) {
        //We are within the bounds
        CurrentCenterPoint = centerPoint;
    } else {
        //We need to clamp or use the center of the screen
        if(visibleArea.contains(sceneBounds)) {
            //Use the center of scene ie. we can see the whole scene
            CurrentCenterPoint = sceneBounds.center();
        } else {
 
            CurrentCenterPoint = centerPoint;
 
            //We need to clamp the center. The centerPoint is too large
            if(centerPoint.x() > bounds.x() + bounds.width()) {
                CurrentCenterPoint.setX(bounds.x() + bounds.width());
            } else if(centerPoint.x() < bounds.x()) {
                CurrentCenterPoint.setX(bounds.x());
            }
 
            if(centerPoint.y() > bounds.y() + bounds.height()) {
                CurrentCenterPoint.setY(bounds.y() + bounds.height());
            } else if(centerPoint.y() < bounds.y()) {
                CurrentCenterPoint.setY(bounds.y());
            }
 
        }
    }
    //Update the scrollbars
	centerOn(centerPoint);
Danke im Voraus! :)

Edit: Zur Information: Qt: 4.7.0 und Mircrosoft Visual Studios 2008, falls weiter Informationen benötigt werden einfach fragen :)
Zuletzt geändert von Eric.E am 14. November 2011 10:12, insgesamt 1-mal geändert.
Eric.E
Beiträge: 16
Registriert: 10. November 2011 11:06

Re: QGV - CenterOn - Stack overflow, keine Scrollbarbewegun

Beitrag von Eric.E »

Problem konnte ich leider immer noch nicht lösen.
Hat jemand vielleicht auch nur eine "Idee", mit der ich
weitermachen könnte (mal vom kompletten umstellen der Widgets abgesehen)
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: QGV - CenterOn - Stack overflow, keine Scrollbarbewegun

Beitrag von franzf »

Aus den Codeschnipseln kann ich jetzt nichts erkennen...
Kannst du alle notewendigen Source-Files in ein .zip packen und über die Forenfunktion "Dateianhang hochladen" hier anhängen? Man sollte dein Projekt dann kompilieren und beim Ausführen dein Problem beobachten können. Bitte keine Binaries/Libs/... ins Zip packen, nicht jeder hat schnelles Internet oder dein OS/Compiler/...
Thx :)
Eric.E
Beiträge: 16
Registriert: 10. November 2011 11:06

Re: QGV - CenterOn - Stack overflow, keine Scrollbarbewegun

Beitrag von Eric.E »

Ich befürchte das wird nicht möglich sein.
Ich darf aus firmeninternen Gründen keinerlei Daten rausgeben,
allerdings bin ich der einzige der am Qt/C++ Projekt arbeitet.
Im Qt kann mir leider niemand so richtig weiterhelfen.

Ich kann hat sicher sagen, dass der Fehler wärend des MouseMoveEvents auftritt, bzw. wärend
des Events in der aufgerufenen Funktion SetCenter.
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: QGV - CenterOn - Stack overflow, keine Scrollbarbewegun

Beitrag von franzf »

Das ist natürlich doof...
Der STack ist begrenzt. Wenn du nicht gerade ein Monsterarray auf dem Stack ablegst, wird ein StackOverflow gerne durch Endlos-Rekursion ausgelöst. SO was seh ich in den Codefetzen nicht. Wenn es wirlich IN SetCenter passieren soll, würde ich sagen, centerOn() ist ein heißer Kandidat. Ist das noch die Version von QGraphicsView, oder hast du die nochmals selber implementiert?

Wenn es nicht geht, den Originalcode zu posten, könntest du versuchen die Strukturen nachzubauen, so dass am Ende das fehlerhafte Verhalten rauskommt. Brauchst ja keine Items reinzulegen...

BTW: In deinem ersten Post schriebst du "Scrollbars bewegen sich nicht, Debugger sagt ich bin drinnen, ohne Debugger StackOverflow". Bezieht sich das "Scrollbars bewegen sich nciht" auf den Lauf im Debugger? Wenn nicht seh ich hier einen kleinen Wiederspruch - entweder rührt sich nichts, oder es gibt den StackOverflow. (Kann aber auch sein, dass ich heut nen schlechten Tag hab und einfach irgendwas nicht peil... :oops: )
Eric.E
Beiträge: 16
Registriert: 10. November 2011 11:06

Re: QGV - CenterOn - Stack overflow, keine Scrollbarbewegun

Beitrag von Eric.E »

Mit dem Stack kenne ich mich über früheres Programmieren von Assambler aus, ja.
Meine Vermutung war, dass er sich irgendwie in den MouseEvents verirrt und diese praktisch nicht korrekt abschließt und diese
so auf dem Stack zur weiteren Bearbeitung vorgemerkt werden.

Wenn du meinst ob ich die QGraphicsView abgeleitet habe, ja habe ich. Brauche ja ziemlich viel zusätzliche Informationen bezügl. CAD-Modellen etc.
Diese QGV existiert so lange, bis ich meinen Button (Icon) nochmals klicke und so diese transparente QGV zerstören.

Die QGV im Mainwindow ist ebenfalls abgeleitet, allerdings weitaus umwangreicher.

Nein du hast das schon eigentlich richtig verstanden:
Wenn ich mit dem Debugger starte und meinen Breakpoint an den "SetCenter" Aufruf setzte, dann hält er während des MouseMoveEvents dort natürlich an.
Die zu diesem Zeitpunkt in den Variablen und Objekten stehenden Werte sind okay. Wenn die Funktion "SetCenter" durchgelaufen ist passiert dann allerdings nichts. Die Scrollbars verschieben sich nicht.
Dummerweise kann ich natürlich das MouseMoveEvent nicht weiterführen, da ich ja im Debugger das Programm weiterlaufen lassen musste, also läuft das MouseReleaseEvent an. Das funktioniert auch einwandfrei.

Wenn ich das Programm ohne Debugger starte, sprich durchlaufen lasse, bekomme ich den StackOverflow.

Ich versuche mal den Code so hier reinzustellen, damit du auch etwas damit anfangen kannst.
Eric.E
Beiträge: 16
Registriert: 10. November 2011 11:06

Re: QGV - CenterOn - Stack overflow, keine Scrollbarbewegun

Beitrag von Eric.E »

So ich werde jetzt den Ablauf bis zum Stackoverflow darstellen, denke dann kann man mir evt helfen.

main.cpp:

Code: Alles auswählen

int main(int argc, char **argv)
{
	QApplication app(argc,argv);
	QString cadFilePath(argv[1]);
	mainWindow *mW = new mainWindow(cadFilePath);
	mW->show();
	return app.exec();
}
Funktionalität sollte verständlich sein.

mainWindow.cpp

Code: Alles auswählen

mainWindow::mainWindow(QString FilePath) : QMainWindow()
{
  // Ini-Datei wird ausgelesen
  // Flags werden gesetzt
  // Menü / Gui wird erstellt.
if(this->isVisible() == true)
{
  *Datei wird nur geöffnet, wenn ein Dateipfad als Konsolenparameter übergeben wurde.*/
  if(FilePath.isEmpty() == false)
  {
    loadFile(FilePath, *ptr_CADBgColor, ptr_CADForce);/*Erstellen des Anzeige-Objektes*/
  }
}	

}
Konstruktor, auf Wesentliches gekürzt. Am Ende des MainWindow-Kontruktors wird dann die Datei geladen, sodenn eine Datei übergeben wurde.

void mainWindow::loadFile(QString cadFilePath, QBrush CADBackgroundColor, QStringList *ptr_CADForce)

Code: Alles auswählen

{
	if(cadFilePath.trimmed().isEmpty() == false)
	{
		/*Liste für das Loggin leeren, bevor die nächste Zeichnung geöffnet wird*/
		ptr_cadLogger->clearLists();
		
		/***********************************************************************************************************/
		/************************************ Fortschrittsdialog für das Laden einer Zeichnung *********************/
		/***********************************************************************************************************/
		QProgressDialog cadProgress(this,Qt::Dialog);
		cadProgress.setAutoClose(true);
		cadProgress.setLabelText("Zeichnung wird geladen...");
		cadProgress.setCancelButton(0);/*keinen Abbrechen Button hinzufügen*/
		cadProgress.setMinimum(0);
		cadProgress.setMaximum(4);
		cadProgress.setMinimumDuration(300);
		cadProgress.setWindowModality(Qt::WindowModal);
		
		cadProgress.setValue(1);
		/***********************************************************************************************************/
		/************************************ cadView-Objekt erstellen *********************************************/
		/***********************************************************************************************************/
		if(bln_gfcSet == true)
		{	
			ptr_CADViewArea->~cadView();	
		}
		ptr_CADViewArea = new cadView(this, cadFilePath, CADBackgroundColor, ptr_CADForce, &bln_adminOn, ptr_cadLogger);
		bln_gfcSet = true;
	
		cadProgress.setValue(2);
		this->setCentralWidget(ptr_CADViewArea);
		cadProgress.setValue(3);
		this->setCentralWidget(ptr_CADViewArea);		
		
		/*Zeichnung auf Bildschirmgröße anpassen*/
		ptr_CADViewArea->fitToScreen();
		cadProgress.setValue(4);
	}

	
}
So, damit wäre die Gui geladen, und die Zeichnung auf ihre Größe angepasst. Jetzt kommt die transparente QGV:
Diese wird beim Klick auf mein Icon erstellt:

void mainWindow::fitToCut()

Code: Alles auswählen

{
  if ( ptr_CADViewArea->Transp_exists == false)
  {		
    ptr_CADView4Cut = new cadViewTransp(ptr_CADViewArea);
    ptr_CADViewArea->ptr_CADScene->addWidget(ptr_CADView4Cut);	
    ptr_CADView4Cut->mouseEvent = true ;
    ptr_CADView4Cut->show() ;
    ptr_CADView4Cut->setWindowOpacity(0.8);	// Überbleibsel, eigentlich nicht benötigt.	
    setChecked(true);
  }
  else
  {
    setChecked(false);
    ptr_CADView4Cut->~cadViewTransp() ;
    ptr_CADViewArea->Transp_exists = false ;		
  }	
}
Konstruktor für QGraphicsViewTranps (cadViewTransp)
cadViewTransp::cadViewTransp(cadView *ptr_Parent)

Code: Alles auswählen

{
  ptr_Parent->Transp_exists = true;
  this->resize(ptr_Parent->ptr_CADScene->width(),ptr_Parent->ptr_CADScene->height());
  this->ptr_Parent = ptr_Parent;
  this->setStyleSheet("background:transparent");
  this->setCursor(Qt::CrossCursor);
  QRubberBand *rubberBand = NULL;
  rBRect = new QRect(0,0,0,0);
}
So, jetzt steht die Transparente QGraphicsView auch.
Mehr Code ist es nicht, der zum StackOverflow führt.
Die MouseEvents und das SetCenter stehen ja schon oben.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: QGV - CenterOn - Stack overflow, keine Scrollbarbewegun

Beitrag von solarix »

Welchem C++-Buch oder welchem Qt-Beispiel hast du dieses schöne Beispiel entnommen:

Code: Alles auswählen

if(bln_gfcSet == true)
{   
    ptr_CADViewArea->~cadView();   
}
ptr_CADViewArea = new cadView(this, cadFilePath, CADBackgroundColor, ptr_CADForce, &bln_adminOn, ptr_cadLogger);
Keine Ahnung ob und was das für einen Einfluss auf dein Programm hat, aber -ehrlich gesagt- es verwundert dann nicht mehr dass bei einem solchen Stil die Übersicht verloren geht und die Software instabil wird..

Genug mit klugscheissgehabe: am Besten wäre ein minimal kompilierbares Beispiel (qmake && make && ./program..) als Attachment...
Eric.E
Beiträge: 16
Registriert: 10. November 2011 11:06

Re: QGV - CenterOn - Stack overflow, keine Scrollbarbewegun

Beitrag von Eric.E »

solarix hat geschrieben:Welchem C++-Buch oder welchem Qt-Beispiel hast du dieses schöne Beispiel entnommen:

Code: Alles auswählen

if(bln_gfcSet == true)
{   
    ptr_CADViewArea->~cadView();   
}
ptr_CADViewArea = new cadView(this, cadFilePath, CADBackgroundColor, ptr_CADForce, &bln_adminOn, ptr_cadLogger);
Keine Ahnung ob und was das für einen Einfluss auf dein Programm hat, aber -ehrlich gesagt- es verwundert dann nicht mehr dass bei einem solchen Stil die Übersicht verloren geht und die Software instabil wird..

Genug mit klugscheissgehabe: am Besten wäre ein minimal kompilierbares Beispiel (qmake && make && ./program..) als Attachment...
Keinem Beispiel, aber schien mir der sinnvollste Weg zu sein nicht 200 QGraphicview übereinander zu legen. Deshalb benutze ich einen einheitlichen Pointer
und beim Laden einer neuen Zeichnung wird die alte gelöscht. Sonst wird auch viel zu viel Speicher alokiert.
Edit: Und auf den GC wollte ich mich nicht verlassen, da allein 2 temporär geladenen CAD-Zeichnungen die kleineren Workstations schon ziemlich belasten.

Zum Thema Stil: Ich habe das Projekt übertragen bekommen, angefangen wurde es von einem DH-Studenten der Wirtschaftinformatik studiert und 6 Monate an diesem Projekt gearbeitet hat... Meine Arbeit beschränkt sich in diesem Teil auf das transparente Widget sowie auf andere in diesem Teil irrelevanten Implementierungen.

^^ Zum Thema minimalkompilierbares Beispiel... Nicht gerade einfach, bei allein grob 100MB externen Bibliotheken usw usf... Aber ich versuche euch bis Mittwoch Mittag etwas entsprechendes vorzulegen. Morgen bin ich nicht im Büro.

Grüße und Danke bis dahin.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: QGV - CenterOn - Stack overflow, keine Scrollbarbewegun

Beitrag von solarix »

Eric.E hat geschrieben: Keinem Beispiel, aber schien mir der sinnvollste Weg zu sein nicht 200 QGraphicview übereinander zu legen. Deshalb benutze ich einen einheitlichen Pointer
und beim Laden einer neuen Zeichnung wird die alte gelöscht. Sonst wird auch viel zu viel Speicher alokiert.
Alles schön und gut, aber du löscht das Objekt ja gar nicht. Das existiert weiterhin. Lies im C++-Buch deiner Wahl (oder Online-Tutorial) bitte nach, wie eine Instanz in C++ gelöscht wird.
Eric.E hat geschrieben: Und auf den GC wollte ich mich nicht verlassen, da allein 2 temporär geladenen CAD-Zeichnungen die kleineren Workstations schon ziemlich belasten.
Da würde ich mich auch nicht darauf verlassen: denn In C++ gibt es keinen GC.

hth..
Eric.E
Beiträge: 16
Registriert: 10. November 2011 11:06

Re: QGV - CenterOn - Stack overflow, keine Scrollbarbewegun

Beitrag von Eric.E »

solarix hat geschrieben: Alles schön und gut, aber du löscht das Objekt ja gar nicht. Das existiert weiterhin. Lies im C++-Buch deiner Wahl (oder Online-Tutorial) bitte nach, wie eine Instanz in C++ gelöscht wird.
Okay, in diesem Fall habe ich selbst wohl etwas falsch verstanden. Denn ich war der Meinung, dass wenn ich per Pointer auf das Objekt "zugreife" und dessen Destruktor aufrufe wird das Objekt gelöscht. Der Pointer besitzt seine Adresse noch, ja aber das Objekt dürfte nichtmehr vorhanden sein, oder?
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: QGV - CenterOn - Stack overflow, keine Scrollbarbewegun

Beitrag von franzf »

Der Destruktor ist nur eine Funktion wie jede andere. Sie wird aufgerufen, um das Objekt zu deinitialisieren - Resourcen freigeben etc. Mehr macht der nicht - vor allem ist der ganze Speicher noch als "benutzt" markiert, du gibst ihn nicht frei! delete ruft zuerst den Destruktor auf, danach gibt es den Speicher auch frei. Mit einem späteren "new" wird dann an vollkommen anderer Stelle im Freispeicher ein anderes Objekt erzeugt, die neue Adresse wird im Zeiger abgespeichert - die alte Adresse ist nicht mehr zu bekommen -> in deinem Fall Speicherleck!
Wenn du also keinen guten Grund hast, auf ein direktes "delete" zu verzichten (z.B. eigenes Speichermanagemenet, späteres placement new, etc.) bleib beim delete :)
Eric.E
Beiträge: 16
Registriert: 10. November 2011 11:06

Re: QGV - CenterOn - Stack overflow, keine Scrollbarbewegun

Beitrag von Eric.E »

franzf hat geschrieben:Der Destruktor ist nur eine Funktion wie jede andere. Sie wird aufgerufen, um das Objekt zu deinitialisieren - Resourcen freigeben etc. Mehr macht der nicht - vor allem ist der ganze Speicher noch als "benutzt" markiert, du gibst ihn nicht frei! delete ruft zuerst den Destruktor auf, danach gibt es den Speicher auch frei. Mit einem späteren "new" wird dann an vollkommen anderer Stelle im Freispeicher ein anderes Objekt erzeugt, die neue Adresse wird im Zeiger abgespeichert - die alte Adresse ist nicht mehr zu bekommen -> in deinem Fall Speicherleck!
Wenn du also keinen guten Grund hast, auf ein direktes "delete" zu verzichten (z.B. eigenes Speichermanagemenet, späteres placement new, etc.) bleib beim delete :)
Ha! Okay,... habe das mal im Debugger und Task-Manager schon mal nachgeschaut und du hattest (natürlich) recht. Bin jetzt den Weg über delete gegangen, bereits schon vor deinem Post, aber jetzt ergibt es auch Sinn.
Mit meinem Problem bin ich leider trotzdem nicht weitergekommen, unter anderem weil ich jetzt an einem Problem hänge, dass ich mir überhaupt nicht erklären kann. (s. Qt Einfach - Forum)

Aber dankeschön :)
Antworten