Zeichenroutine optimieren
Zeichenroutine optimieren
hallo,
ich verwende ein Tabwidget mit mehreren Reitern. Einer der Reiter stellt eine Map dar. Diese wird jedesmal neu gezeichnet sobald sich etwas an der Map verändert. Leider wird das paintEvent auch immer dann ausgelöst wenn ich die Reiter wechsel. Dies ist jedoch nicht nötig, weil dich an der Kartendarstellung nichts ändert. Kann ich das irgendwie umgehen bzw dafür sorgen das in diesem Fall das paintEvent nicht ausgelöst wird ?
ich verwende ein Tabwidget mit mehreren Reitern. Einer der Reiter stellt eine Map dar. Diese wird jedesmal neu gezeichnet sobald sich etwas an der Map verändert. Leider wird das paintEvent auch immer dann ausgelöst wenn ich die Reiter wechsel. Dies ist jedoch nicht nötig, weil dich an der Kartendarstellung nichts ändert. Kann ich das irgendwie umgehen bzw dafür sorgen das in diesem Fall das paintEvent nicht ausgelöst wird ?
Zuletzt geändert von marvel am 12. Mai 2011 00:04, insgesamt 1-mal geändert.
Hallo nochmal,
ich weiß der Beitrag ist schon etwas älter, jedoch sitze ich seit kurzem wieder an meiner App. Ich konnte das mit der QPixmap nicht ganz nachvollziehen, meinst Du ich soll das Widget zwischenspeichern ? Für eine Erläuterung wäre ich dankbar.
Darüberhinaus habe ich noch andere Probleme...
Ich habe ein QMainWindow mit einem QTabWidget. In das QTabWidget schmeisse ich mehrere QWidgets rein. in einem der QWidgets benutze ich die QPaintEvent-Methode. Das QWidget besitzt zusätzlich einen QPushButton. Der QPushbutton ist mit keinem Slot verbunden, er wurde lediglich einmal durch die setupUI() Methode ins Leben gerufen. Jetzt verhält sich der Button etwas mysteriös, wenn ich auf ihn klicke dann löst er direkt zweimal die PaintEvent-Methode aus. Ich dachte eigentlich das die PaintEvent Methode erst bei Veränderung ausgelöst wird, doch scheinbar reicht schon ein Klick auf einen leblosen Button aus. Wäre nur die Frage zu klären warum er direkt zweimal auslöst anstatt einmal ?
Das einzige was ich mir vorstellen kann ist das zwischen press & release Button unterschieden wird und so zweimal die PaintEvent Methode aufgerufen wird.
ich weiß der Beitrag ist schon etwas älter, jedoch sitze ich seit kurzem wieder an meiner App. Ich konnte das mit der QPixmap nicht ganz nachvollziehen, meinst Du ich soll das Widget zwischenspeichern ? Für eine Erläuterung wäre ich dankbar.
Darüberhinaus habe ich noch andere Probleme...
Ich habe ein QMainWindow mit einem QTabWidget. In das QTabWidget schmeisse ich mehrere QWidgets rein. in einem der QWidgets benutze ich die QPaintEvent-Methode. Das QWidget besitzt zusätzlich einen QPushButton. Der QPushbutton ist mit keinem Slot verbunden, er wurde lediglich einmal durch die setupUI() Methode ins Leben gerufen. Jetzt verhält sich der Button etwas mysteriös, wenn ich auf ihn klicke dann löst er direkt zweimal die PaintEvent-Methode aus. Ich dachte eigentlich das die PaintEvent Methode erst bei Veränderung ausgelöst wird, doch scheinbar reicht schon ein Klick auf einen leblosen Button aus. Wäre nur die Frage zu klären warum er direkt zweimal auslöst anstatt einmal ?
Das einzige was ich mir vorstellen kann ist das zwischen press & release Button unterschieden wird und so zweimal die PaintEvent Methode aufgerufen wird.
Was Upsala wohl indirekt annahm: Du willst das paintEvent unterdrücken, weil das Zeichnen lange dauert und dadurch deine Anwendung beim Tabwechsel laggt. Ein Pixmap ist schnell gezeichnet, deshalb an geeigneten Stellen (resizeEvent, zoom, ...) auf ein Pixmap malen und dieses dann im paintevent malen.
Sollte dein Wunsch nicht aus einem Performanceproblem entstanden sein: lass es, mach dir keine Gedanken, ist halt so.
Zu deinem neuen Problem: Liegt der Button auf dem Widget? Malt der nen Holo oder anderen Effekt beim press? Das sollte einen repaint triggern.
Sollte dein Wunsch nicht aus einem Performanceproblem entstanden sein: lass es, mach dir keine Gedanken, ist halt so.
Zu deinem neuen Problem: Liegt der Button auf dem Widget? Malt der nen Holo oder anderen Effekt beim press? Das sollte einen repaint triggern.
Hallo franzf,
ich bin Dir sehr dankbar das Du mir Rede und Antwort stehst, ich bin nämlich langsam am verzweifeln. Wie Du am Post erkennen kannst schlage ich mir die Nächte um die Ohren, weil ich einfach nicht weiterkomme. Ich habe die Buttons jetzt erstmal komplett rausgenommen, weil ich damit nur eine Verschiebung in der Karte simulieren wollte. Ich habe leider immer noch einige Probleme die ich durch unzählige Testerei nicht bewältigen konnte. Im Grunde soll das ganze wie folgt ablaufen: Ich klicke im TabWidget auf den Reiter Files und lese eine Datei ein.Die Datei enthält mehrere unterschiedliche Objekte. Ein Objekt hat mehrere Koordinaten. Wenn die Datei abgearbeitet wurde werden die Objekte in einem QPainterPath vorbereitet und in einer Liste abgelegt. Sobald ich nun auf den Reiter Map klicke soll anhand der Liste von QPainterPath die Karte gezeichnet werden. Ich zeichne direkt ins Widget. Wenn ich in der Karte mit der Maus klicke wird die Karte entsprechend zentriert bzw die Zeichenroutine neu angestoßen. Bei einer großen Anzahl an Objekten kann das Zeichnen der Karte bis zu 20 Sekunden und länger dauern. Gibt es eine Möglichkeit diesen Vorgang zu optimieren oder sollte ich einen anderen Ansatz wählen ?
ich bin Dir sehr dankbar das Du mir Rede und Antwort stehst, ich bin nämlich langsam am verzweifeln. Wie Du am Post erkennen kannst schlage ich mir die Nächte um die Ohren, weil ich einfach nicht weiterkomme. Ich habe die Buttons jetzt erstmal komplett rausgenommen, weil ich damit nur eine Verschiebung in der Karte simulieren wollte. Ich habe leider immer noch einige Probleme die ich durch unzählige Testerei nicht bewältigen konnte. Im Grunde soll das ganze wie folgt ablaufen: Ich klicke im TabWidget auf den Reiter Files und lese eine Datei ein.Die Datei enthält mehrere unterschiedliche Objekte. Ein Objekt hat mehrere Koordinaten. Wenn die Datei abgearbeitet wurde werden die Objekte in einem QPainterPath vorbereitet und in einer Liste abgelegt. Sobald ich nun auf den Reiter Map klicke soll anhand der Liste von QPainterPath die Karte gezeichnet werden. Ich zeichne direkt ins Widget. Wenn ich in der Karte mit der Maus klicke wird die Karte entsprechend zentriert bzw die Zeichenroutine neu angestoßen. Bei einer großen Anzahl an Objekten kann das Zeichnen der Karte bis zu 20 Sekunden und länger dauern. Gibt es eine Möglichkeit diesen Vorgang zu optimieren oder sollte ich einen anderen Ansatz wählen ?
Ich habe nochmals meine gesamte Zeichenroutine durchleuchtet und bin mit meinem Latein wirklich am Ende. Bei einer gewissen Anzahl an Objekten macht mein Programm einfach nicht mehr mit. Ich bekomme folgende Fehlermeldung :
Auch mein Versuch erst in eine QPixmap zu schreiben und dann das ganze aufs QWidget zu übertragen hat leider nichts gebracht. Ich bekomme folgende Meldung:
Ich habe versucht an allen Stellen zu optimieren, jedoch ohne Erfolg. Ich programmiere wie schon erwähnt für Windows Mobile. Muss ich mich eventuell damit geschlagen geben das es einfach nicht umsetzbar ist aufgrund fehlender Ressourcen oder kann ich noch irgendwas optimieren oder verändern am Zeichnen ?
Code: Alles auswählen
Zu zeichnendes Objekt: "rail"
Anzahl aller "rail" Objekte: 4498
Anzahl der zu zeichnenden "rail" Objekte: 2342
RaiseException: Thread=9cb24964 Proc=80097280 'oac.exe'
AKY=00010001 PC=03f8eb28(coredll.dll+0x00044b28) RA=88037900(NK.EXE+0x00007900) BVA=00000000 FSR=00000000
Unhandled exception at 0x03f8eb28 in oac.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x2364fe24..
Das Programm "[0xBC5E8806] oac.exe" wurde mit Code 1067 (0x42b) beendet.Code: Alles auswählen
QImage: out of memory, returning null image
libpng warning: Image width is zero in IHDR
libpng warning: Image height is zero in IHDR
libpng error: Invalid IHDR dataIch habe versucht an allen Stellen zu optimieren, jedoch ohne Erfolg. Ich programmiere wie schon erwähnt für Windows Mobile. Muss ich mich eventuell damit geschlagen geben das es einfach nicht umsetzbar ist aufgrund fehlender Ressourcen oder kann ich noch irgendwas optimieren oder verändern am Zeichnen ?
Hallo marvel,
Unter 32bit Windows habe ich auch das Problem, das das Laden großer Daten meine Anwendung an die 2GB Speichergrenze eines Prozesses bringt. Wenn man da nicht überall prüft, oder mit try/catch die Exceptions fängt, rumsts.
ich weiss nicht wieviel Speicher deiner Anwendung unter Windows Mobile zur Verfügung steht, aber an der Stelle hast du versucht ein QImage zu alloziieren und das Ergebnis nicht geprüft. Der Speicher scheint voll zu sein.marvel hat geschrieben:Code: Alles auswählen
QImage: out of memory, returning null image libpng warning: Image width is zero in IHDR libpng warning: Image height is zero in IHDR libpng error: Invalid IHDR data
Unter 32bit Windows habe ich auch das Problem, das das Laden großer Daten meine Anwendung an die 2GB Speichergrenze eines Prozesses bringt. Wenn man da nicht überall prüft, oder mit try/catch die Exceptions fängt, rumsts.
Hallo,
ich wüsste nicht an welcher Stelle bzw wie ich überpürfen kann wann und wieviel Speicher alloziert wird. Ich habe folgendes Konstrukt:
Jedes Mal wenn ich im TabWidget auf den Reiter Map klicke wird die paintEvent Methode aufgerufen. In der paintEvent Methode wird die Methode createMap aufgerufen und dieser sowohl der painter als auch verschiedene Paramter für die Kartendarstellung weitergegeben. Das Zeichnen wird dann hier vorbereitet:
Am Ende wird hier gezeichnet:
Es können teilweise bis zu 7000 PainterPath Objekte in einem SChleifendurchlauf abgearbeitet werden, meistens knallt es dann auch. Kostet jede drawPath() Aufruf zu viel Speicher oder muss ich vorher den Speicher wieder freigeben ? Wo und wie kann ich überprüfen ob noch genug SPeicher vorhanden ist bzw Exceptions abfangen ?
ich wüsste nicht an welcher Stelle bzw wie ich überpürfen kann wann und wieviel Speicher alloziert wird. Ich habe folgendes Konstrukt:
Code: Alles auswählen
void GUI_Map::paintEvent(QPaintEvent* event)
{
qDebug() << "PaintEvent";
QPixmap pixmap(width(),height());
QPainter painter(&pixmap);
// Maßstab setzen
double x = ((double)width() /(double)physicalDpiX()) * 2.54 * 5;
double y = ((double)height() /(double)physicalDpiY()) * 2.54 * 5;
// Skala für den sichtbaren Bereich auf- oder abrunden.
int xRange = (x*1+0.5)/1.0;
int yRange = (y*1+0.5)/1.0;
_oac_map->createMap(&painter,this->width(),this->height(),_xMousePos,_yMousePos,xRange,yRange);
pixmap.save("path.png");
}Code: Alles auswählen
void OAC_Map::createMap(QPainter *painter, int physicalXRange, int physicalYRange, int xMousePos, int yMousePos, int logicalXRange, int logicalYRange)
{
// Die ermittelten Kacheln zeichnen.
for(int i=0; i<_tileList.size(); i++)
{
for(int k=0; k<_drawOrder.size(); k++)
{
if(_tileList.at(i)->getHashLayer().contains(_drawOrder.at(k)))
{
qDebug() << _drawOrder.at(k);
OAC_Layer *layer = _tileList.at(i)->getHashLayer().value(_drawOrder.at(k));
if(layer->getViewable())
{
qDebug() << "Anzahl aller Objekte: " << layer->getObjectList().size();
for(int x=0; x< layer->getObjectList().size(); x++)
{
OAC_Object *object = layer->getObjectList().at(x);
QRectF objectBounding = object->getPainterPath().boundingRect();
QRectF viewBounding(_viewMinLon,_viewMaxLat,logicalXRange,-logicalYRange);
if(objectBounding.intersects(viewBounding))
{
layer->getObjectsToDraw().append(object);
}
}
qDebug() << "Anzahl der zu zeichnende Objekte: " << layer->getObjectsToDraw().size();
layer->drawObjects(painter);
layer->wait();
}
}
}
}Code: Alles auswählen
void OAC_Layer::drawObjects(QPainter *p)
{
_painter = p;
_painter->setBrush(_brush);
_painter->setPen(_pen);
start();
}
void OAC_Layer::run()
{
while(!_objectsToDraw.isEmpty())
{
_painter->drawPath(_objectsToDraw.takeLast()->getPainterPath());
}
}-
Christian81
- Beiträge: 7319
- Registriert: 26. August 2004 14:11
- Wohnort: Bremen
- Kontaktdaten:
Das das überhaupt funktioniert ist ein Wunder... ich gehe mal davon aus dass OAC_Layer ein separater Thread ist.
Er würde also bei jedem GUI_Map::paintEvent() neu gestartet. Außerdem übergibst Du ein QPainter-Pointer an den Thread aber der Pointer (bzw. das Objekt lebt nicht wirklich lang... und dann sind QPixmaps außerhalb des Main-Threads nicht zu verwenden (auch wenns kein Bug ist, siehe z.B. http://bugreports.qt.nokia.com/browse/QTBUG-7848 )
Er würde also bei jedem GUI_Map::paintEvent() neu gestartet. Außerdem übergibst Du ein QPainter-Pointer an den Thread aber der Pointer (bzw. das Objekt lebt nicht wirklich lang... und dann sind QPixmaps außerhalb des Main-Threads nicht zu verwenden (auch wenns kein Bug ist, siehe z.B. http://bugreports.qt.nokia.com/browse/QTBUG-7848 )
MfG Christian
'Funktioniert nicht' ist keine Fehlerbeschreibung
'Funktioniert nicht' ist keine Fehlerbeschreibung
OAC_Layer ist ein seperater Thread. Den Thread habe ich eingebaut in der Hoffnung das beim klicken auf mein Widget das Fenster nicht blockiert, also erst das Fenster angezeigt wird und im Hintergrund der Thread abgearbeitet wird. Auch ohne den Thread bricht das Programm irgendwann ab. Ich möchte auf das QPainter Objekt eingehen. Dieses stirbt doch erst wenn die paintEvent Methode abgearbeitet ist oder ? Ich sehe nämlich kein Problem mit der Lebensdauer...erkennst Du einen Fehler ?Das das überhaupt funktioniert ist ein Wunder... ich gehe mal davon aus dass OAC_Layer ein separater Thread ist.
Er würde also bei jedem GUI_Map::paintEvent() neu gestartet. Außerdem übergibst Du ein QPainter-Pointer an den Thread aber der Pointer (bzw. das Objekt lebt nicht wirklich lang... und dann sind QPixmaps außerhalb des Main-Threads nicht zu verwenden (auch wenns kein Bug ist, siehe z.B. http://bugreports.qt.nokia.com/browse/QTBUG-7848 )
Lassen wir mal die QPixmap Geschichte erstmal weg. Es soll also direkt ins Widget gezeichnet werden.
Code: Alles auswählen
void GUI_Map::paintEvent(QPaintEvent* event)
{
qDebug() << "PaintEvent";
QPainter painter(this);
// Maßstab setzen
double x = ((double)width() /(double)physicalDpiX()) * 2.54 * 5;
double y = ((double)height() /(double)physicalDpiY()) * 2.54 * 5;
// Skala für den sichtbaren Bereich auf- oder abrunden.
int xRange = (x*1+0.5)/1.0;
int yRange = (y*1+0.5)/1.0;
_oac_map->createMap(&painter,this->width(),this->height(),_xMousePos,_yMousePos,xRange,yRange);
}-
Christian81
- Beiträge: 7319
- Registriert: 26. August 2004 14:11
- Wohnort: Bremen
- Kontaktdaten:
Ich habe layer->wait(); im Code übersehen. Aber da nützt ein Thread ja erst recht nichts wenn der Hauptthread eh auf den anderen Thread wartet... abgesehen davon wäre immer noch das Problem mit QPixmap/QWidget zeichnen in einem separaten Thread was nicht erlaubt ist.
Und wenn das Programm crasht gibt es einen Debugger und/oder valgrind mit denen man nachschauen kann wo und warum es crasht.
Und wenn das Programm crasht gibt es einen Debugger und/oder valgrind mit denen man nachschauen kann wo und warum es crasht.
MfG Christian
'Funktioniert nicht' ist keine Fehlerbeschreibung
'Funktioniert nicht' ist keine Fehlerbeschreibung
Hallo liebe Community,
ich neige mich langsam dem Ende meiner Diplomarbeit zu und habe noch ein paar kleine Bugs die ich gerne beseitigen würde. Ich hatte schon damals ein bestimmtes Problem angesprochen, jedoch keine Lösung gefunden und erstmal das ganze bis heute aufgeschoben.
Problemstellung:
Ich habe ein QTabWidget mit mehreren Tabs. In einem der Tabs habe ich die paintEvent Methode reimplementiert. Sobald der Tab aufgerufen wird löst die paintEvent Methode aus. Zusätzlich habe ich im Tab bzw im Widget einen QToolButton eingebaut. Dieser Button ist mit keinem Slot verbunden, er wurde lediglich einmal durch die setupUI() Methode ins Leben gerufen und ist vorerst leblos. Dennoch wird bei einem Klick auf den Button gleich zweimal die paintevent Methode aufgerufen. Dies möchte ich irgendwie unterbinden. Gibt es eine Möglichkeit dieses Verhalten zu ändern oder kennt jmd eine Alternative ?
Für eine Lösung wäre ich sehr dankbar, da meine Diplomarbeit davon abhängt und ich nur noch sehr wenig Zeit habe das Problem zu lösen. Danke im vorraus für die Hilfe
ich neige mich langsam dem Ende meiner Diplomarbeit zu und habe noch ein paar kleine Bugs die ich gerne beseitigen würde. Ich hatte schon damals ein bestimmtes Problem angesprochen, jedoch keine Lösung gefunden und erstmal das ganze bis heute aufgeschoben.
Problemstellung:
Ich habe ein QTabWidget mit mehreren Tabs. In einem der Tabs habe ich die paintEvent Methode reimplementiert. Sobald der Tab aufgerufen wird löst die paintEvent Methode aus. Zusätzlich habe ich im Tab bzw im Widget einen QToolButton eingebaut. Dieser Button ist mit keinem Slot verbunden, er wurde lediglich einmal durch die setupUI() Methode ins Leben gerufen und ist vorerst leblos. Dennoch wird bei einem Klick auf den Button gleich zweimal die paintevent Methode aufgerufen. Dies möchte ich irgendwie unterbinden. Gibt es eine Möglichkeit dieses Verhalten zu ändern oder kennt jmd eine Alternative ?
Für eine Lösung wäre ich sehr dankbar, da meine Diplomarbeit davon abhängt und ich nur noch sehr wenig Zeit habe das Problem zu lösen. Danke im vorraus für die Hilfe