C++ Qt Druckfunktion

Icewurm

Lt. Junior Grade
Registriert
Juli 2006
Beiträge
274
Hallo,
Ich habe wieder einmal ein dummes Problem, das mich schon etliche Stunden gekostet hat. Vielleicht hat von euch wer eine Idee:

Der folgende Code soll eine dynamisch erstellte Html-Seite drucken. Das macht er auch, aber nur beim ersten Aufruf. Danach wird das Signal paintRequested nicht mehr aufgerufen und der Inhalt von der Druckvorschau wird nicht mehr aktualisiert.

Beim Klick auf drucken in der Druckvorschau wird dann aber doch das neue Dokument gedruckt (nicht das alte Angezeigte weil dann auch die Funktion (SLOT) printPreview aufgerufen wird).

Was hab ich da übersehen?

Code:
#include "printfunctions.h"

PrintFunctions::PrintFunctions(QObject *parent):QObject(parent)
{
    rezPrinter = new QPrinter();
    dialog = new QPrintDialog(rezPrinter);
    prevDialog = new QPrintPreviewDialog(rezPrinter);

    connect(prevDialog, SIGNAL(paintRequested(QPrinter *)), SLOT(printPreview(QPrinter *)));
}

PrintFunctions::~PrintFunctions()
{
    delete rezPrinter;
    delete dialog;
    delete prevDialog;
}

bool PrintFunctions::printHTML(QString strHtml, bool showPreview)
{   
    this->strHtml = strHtml;

    if (showPreview == true)
    {
        if(prevDialog->exec() == QDialog::Rejected)
        {
            return false;
        }
    }
    else
    {
        if(dialog->exec() == QDialog::Rejected)
        {
            return false;
        }

        QTextEdit te;
        te.setHtml(strHtml);
        te.print(rezPrinter);
    }

    return true;
}

void PrintFunctions::printPreview(QPrinter *printer)
{
    QTextEdit te;
    te.setHtml(strHtml);
    te.print(printer);
}
 
Zuletzt bearbeitet:
Hallo,

der QPrintPreviewDialog sendet das Signal paintRequested() nur, wenn er die Druckvorschau neu generieren muss (siehe Doku). Da du den Dialog aber im Konstruktor erzeugst und dann mit exec() mehrfach wiederverwendest, vermute ich, dass er die erste Vorschau intern noch gespeichert hat und diese ab dem zweiten Aufruf einfach unverändert anzeigt. Woher soll der Dialog auch wissen, dass sich der Inhalt geändert hat?

Um das zu prüfen, kannst du den Vorschau-Dialog ja mal als lokale Variable in PrintFunctions::printHTML() erzeugen:

Code:
if (showPreview)
{
    QPrintPreviewDialog previewDialog(rezPrinter);
    connect(previewDialog, SIGNAL(paintRequested(QPrinter *)), SLOT(printPreview(QPrinter *)));

    if(previewDialog->exec() == QDialog::Rejected)
    {
        return false;
    }
}

Auf diese Weise sollte das Signal bei jedem Dialogaufruf ausgesendet werden.
 
Danke für die Antwort.

Deine Lösung funktioniert. So hatte ich es auch als Workaround drin, aber geht das nicht besser?

Beim ersten Mal werden die Daten über das Signal ja nur geladen weil rezPrinter und prevDialog leer sind. Ich lade die Daten ja nicht im Konstruktor.

Ich habe jetzt aber keine Funktion gefunden um den Dialog zurückzusetzen. Finde ich komisch.
 
Ich finde die Lösung gar nicht so unelegant. Immerhin gilt in der Programmierung i.d.R. das "Prinzip der Lokalität", d.h. Variablen sollten so lokal wie möglich definiert werden. Ich sehe hier eigentlich keinen Grund, den Dialog an die Lebenszeit deiner Klasse PrintFunctions zu koppeln (du rufst den Dialog schließlich modal auf und machst somit im Programm auch erst weiter, wenn er geschlossen wurde). Eine MessageBox erzeugst du ja auch lokal bei Bedarf, anstatt ein globales Objekt vorzuhalten und dieses dann mehrfach wiederzuverwenden.

Falls du wirklich einen Workaround einsetzen möchtest: Der QPrintPreviewDialog enthält intern ein QPrintPreviewWidget. Letzteres besitzt einen Slot namens updatePreview(), welchen du rufen kannst, um anzuzeigen, dass sich der Druckinhalt geändert hat. Daraufhin sollte das Widget dann automatisch über Aussendung von paintRequested() den neuen Inhalt anfordern.

Du könntest also entweder deinen eigenen Dialog um QPrintPreviewWidget herum konstruieren oder du nutzt folgende Variante, um an das interne Widget deines vorgefertigten Dialogs zu kommen:

Code:
QPrintPreviewWidget* w = prevDialog->findChild<QPrintPreviewWidget*>();

// ...
// ...
// Wenn sich der Druckinhalt geändert hat
w->updatePreview();
 
Ok. Du hast mich überzeugt. Man muss es ja nicht unnötig verkomplizieren.
 
OK, den QPrintDialog würde ich dann analog behandeln und in dem else-Zweig als lokale Variable auf dem Stack erzeugen.

Ein Tipp am Rande:

Wenn du dann noch den QPrinter als member deiner Klasse deklarierst, anstatt ihn mit new auf dem Head zu erzeugen, kannst du auch noch die letzte der drei delete-Operationen streichen und dir somit den Destruktur deiner Klasse komplett sparen. ;)

delete-Anweisungen sind in modernem C++ nur noch in Ausnahmefällen erforderlich.
 

Ähnliche Themen

Antworten
2
Aufrufe
3.669
Zurück
Oben