Unsolved QPrintPreviewDialog crashes on selecting print button.
-
I am using qt version qt-5.6.1 . I have created a QPrintPreviewDialog. My application crashes when I select print button inside PrintPreview dialog.
My Question is -
Is there any known bug with QPrintPreviewDialog in Qt version 5.6.1 ?
or I am doing something wrong?Please review my code.
Below is the implementation I am trying to test.
QPrinter m_printer; //class member
QPainter m_painter; //class memberm_printer.setFullPage(true);
bool MyPrinter:: openPrintPreviewDialog(QWidget* parent)
{
QPrintPreviewDialog printPreviewDialog = new QPrintPreviewDialog(&m_printer, pParent);
connect(printPreviewDialog,SIGNAL(paintRequested(QPrinter)),this,SLOT(print(QPrinter*)));
if (printPreviewDialog->exec() != QDialog::Accepted)
{
return false;
}
else
return true;....
void MyPrinter::print(QPrinter* p)
{
m_painter.setRenderHints(QPainter::Antialiasing |
QPainter::TextAntialiasing |
QPainter::SmoothPixmapTransform, true);
m_painter.begin(&m_printer);
m_painter.drawText(rect, Qt::AlignLeft, "Created at: " + time); // assume rect , time is defined
} -
Not sure if it causes the crash but you don't need to keep the painter as a member.
It is ok to just created it in the print function and then let it go out of scope.
Also, I think you should use the printer passed into the print function because that it what it is there for!
Calling p->newPage() at the start of the print would be a good idea too. -
@Sheetal Did you try to debug your app to see where exactly it crashes? Do you have a stack trace?
-
@Sheetal If you are still interested in an answer to this question...
There are several problems with the code you pasted, I am surprised it even compiles, for example.
connect(printPreviewDialog,SIGNAL(paintRequested(QPrinter)),this,SLOT(print(QPrinter*)));
must have a QPrinter pointer for the SIGNAL function as in SIGNAL(paintRequested(QPrinter*)).
I am assuming your MyPrinter class is derived from a QWidget, although this is not clear from your code snippets, and assuming you have actually defined the print function as a slot.
If this is the case then you should test that the printer is valid before you use it with the painter in the print function. If it is not valid i.e. you don't have printer set up properly the behaviour will be undefined and might be the reason for the crash.
Next assuming you get past that you should add m_painter.end() to the end of the print function so you can actually see what you draw on the paper in the preview.
If you did not define the painter as a member function that would have happened when the painter when out of scope.As @jsulm said you should debug your code to see where it is crashing. If you want more help from here you should also post a more complete code sample.
Also what version of Qt, and the OS you are using would be helpful. -
Thanks for the reply.
I forgot to mention that this crash is sporadic. It happens only sometimes.
It happens in my product , because of copyright I can not post the full call stack.
@kenchan Sorry for the typo. Its QPainter* . code is compiling . I have defined print(QPrinter*) as a slot.
connect(printPreviewDialog,SIGNAL(paintRequested(QPrinter*)),this,SLOT(print(QPrinter*)));MyPrinter class is derived from QObject
class MyPrinter : public QObject
{
Q_OBJECT
...
};I have passed m_printer in below call-
QPrintPreviewDialog printPreviewDialog = new QPrintPreviewDialog(&m_printer, pParent);
m_printer is initialized in constructor.
MyPrinter :: MyPrinter() :m_printer(QPrinter::HighResolution)
{
m_printer.setFullPage(true);
m_printer.setOutputFileName(path);
}In the slot paint() , I have made sure that m_printer is valid.
Here, I assume pointer p and m_printer are both same. When I print value of &m_printer
value of p both print the same address. that means p is pointing to m_printer .
void MyPrinter::print(QPrinter* p)
{
m_painter.setRenderHints(QPainter::Antialiasing |
QPainter::TextAntialiasing |
QPainter::SmoothPixmapTransform, true);
printBegin();
printHeader(); // this uses drawText()
printImage(image); //this uses drawImage()
printEnd(); // calls m_painter.end();
}
printBegin()
{
m_painter.begin(&m_printer);
}Here printHeader & printImage both are using m_printer & m_painter objects that is the reason I made it class member.
I am using Qt5.6.1 & Red Hat Enterprise Linux Server release 7.3 (Maipo)
Any idea Qt5.6.1 has a bug ? or my code has problem.. I am not finding any clue.
-
@Sheetal OK, thanks for posting that. Did you debug and find where it crashes yet?
-
@Kenchan Will post the debugging result once I am able to reproduce. It is Sporadic. It happens only once in a while. In last 10 days it happened only 2-3 times. That is the problem.
call stack when last time it crashed. This may not help as it is not full call stack. But still.
Thu Nov 30 18:59:44 2017 Logger.cpp logStackTrace : 670 Stack Trace: Segmentation Fault
/usr/local/qt/lib/libQt5PrintSupport.so.5(+0x38a62) [0x7fa8d35b1a62]
/usr/local/qt/lib/libQt5PrintSupport.so.5(+0x4f563) [0x7fa8d35c8563]
/usr/local/qt/lib/libQt5Core.so.5(_ZN11QMetaObject8activateEP7QObjectiiPPv+0x2c1) [0x7fa8d23bf521]
/usr/local/qt/lib/libQt5Widgets.so.5(_ZN9QLineEdit13focusOutEventEP11QFocusEvent+0x89) [0x7fa8d31b8189]
/usr/local/qt/lib/libQt5Widgets.so.5(_ZN7QWidget5eventEP6QEvent+0x57c) [0x7fa8d30c7cfc]
/usr/local/qt/lib/libQt5Widgets.so.5(_ZN9QLineEdit5eventEP6QEvent+0x65) [0x7fa8d31b7ba5]
/usr/local/qt/lib/libQt5Widgets.so.5(_ZN7QWidget5eventEP6QEvent+0x57c) [0x7fa8d30c7cfc]
/usr/local/qt/lib/libQt5Widgets.so.5(_ZN9QComboBox5eventEP6QEvent+0x76) [0x7fa8d31783b6]
/usr/local/qt/lib/libQt5Widgets.so.5(_ZN19QApplicationPrivate13notify_helperEP7QObjectP6QEvent+0x9c) [0x7fa8d308632c]
/usr/local/qt/lib/libQt5Widgets.so.5(_ZN12QApplication6notifyEP7QObjectP6QEvent+0x3fa) [0x7fa8d308a98a] -
@Sheetal OK, i can't see anything in the code that will directly cause a crash. I would be concerned about keeping the m_printer in sync with what the preview dialog settings. Since you are not using the pointer that gets passed into the print function from the print preview dialog your member function will not get updated with those setting. As you are forcing it to print to a pdf file maybe this is not so important.
I have been using the QPrintPreviewWidget in my own dialog since before 5.6.0 an have not seen intermittent crashes. I only ever had problems with the printer object not being valid in some way but I make sure that does not happen any more.
I only use the printer pointer passed into the print function and sync my current printer and it's settings from the one currently managed by the widget, which may or may not be the one I passed to it in the first place.
-
@Sheetal you are right, not very useful...
BTW, I only use this on Windows and the macOS so don't know how it behaves on Linux. -
Thanks for the reply @kenchan . Will definitely try changing the m_printer to the one passed in the print() slot. (In this case "p")
Will post the results. -
@Sheetal Another thing that concerns me is keeping the painter as a class member. Looking at the code you could create it on each call in the print function and pass it as a pointer to the other functions that need it when they are called from the print function. The painter would go out of scope at the end of the print function. I am not used to using a painter in any other way, I believe there are restrictions on how and when a painter can be used.
-
-
@Kenchan . Ok. I got your point regarding painter. Will create a local painter object . Thanks for confirming bug report.
-
@kenchan said in QPrintPreviewDialog crashes on selecting print button.:
I only use the printer pointer passed into the print function and sync my current printer and it's settings from the one currently managed by the widget, which may or may not be the one I passed to it in the first place.
I did not get "sync my current printer and it's settings from the one currently managed by the widget, which may or may not be the one I passed to it in the first place."
U mean , I should have a m_printer pointer as class member and pass it to QPrintPreviewDialog(), and then in print(QPainter p) slot I should assign p=m_printer?
-
@Sheetal Well, As it tells you in the docs for the QPrintPreviewDialog, you can let the dialog provide a printer or you provide it with one.
You can have a printer member as a pointer or as you have it now, but you must know that the user can change the printer and or it settings using the dialog. This means the type of printer and or its settings may change between when the dialog is created and when the print function is called. You must allow for that by and make sure the printer is what you expect when you do the drawing on it.When I use my dialog I do the following:
I get a pointer to the default printer make any settings I want to set then pass it to the dialog in its constructor.
I make the connection to the print function.
I call exec on the dialog.
The print function is called.
I use the printer pointer passed in and create a painter with it.
I draw on the painter.
The dialog shows the user the preview.
The user may change the paper size or even the printer etc. The print function can be called again when a change is made.
The user clicks the print button.
The pages get printed to the printer or pdf file whichever the case maybe.
The dialog closes.
I delete the printer.I hope this helps.
-
I am able to get the complete call stack when it crashed. It is as below.
There is no problem with painter & printer objects (I have corrected my code as per our previous discussion ). When I debug all calls are made correctly. Nothing suspicious .
But, looks like when QPrintPreviewDialog is getting destroyed by Qt at the end of printing there is a problem. or Maybe some events are getting generated after preview dialog is closed.
1 CLogger::handleSignal Logger.cpp 618 0x7fe3529e1f27
2 __restore_rt 0x7fe34d06e250
3 ?? 0x180a090
4 QPrintPreviewWidgetPrivate::setZoomFactor(double) 0x7fe34f87fa65
5 QPrintPreviewDialogPrivate::_q_zoomFactorChanged() 0x7fe34f896563
6 QMetaObject::activate(QObject *, int, int, void * *) 0x7fe34e68d521
7 QLineEdit::focusOutEvent(QFocusEvent *) 0x7fe34f486189
8 QWidget::event(QEvent *) 0x7fe34f395cfc
9 QLineEdit::event(QEvent *) 0x7fe34f485ba5
10 QWidget::event(QEvent *) 0x7fe34f395cfc
11 QComboBox::event(QEvent *) 0x7fe34f4463b6
12 QApplicationPrivate::notify_helper(QObject *, QEvent *) 0x7fe34f35432c
13 QApplication::notify(QObject *, QEvent *) 0x7fe34f35898a
14 OdvApplication::notify OdvApplication.cpp 53 0x63d13d
15 QCoreApplication::notifyInternal2(QObject *, QEvent *) 0x7fe34e663a75
16 QApplicationPrivate::setFocusWidget(QWidget *, Qt::FocusReason) 0x7fe34f3565c3
17 QApplication::setActiveWindow(QWidget *) 0x7fe34f356c14
18 QApplicationPrivate::notifyActiveWindowChange(QWindow *) 0x7fe34f356cc3
19 QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate::ActivatedWindowEvent *) 0x7fe34e9b4635
20 QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *) 0x7fe34e9b498d
21 QWindowSystemInterface::sendWindowSystemEvents(QFlagsQEventLoop::ProcessEventsFlag) 0x7fe34e99696b
22 userEventSourceDispatch(_GSource *, int ( *)(void *), void *) 0x7fe34e2d9cb0
23 g_main_context_dispatch 0x7fe3470b5d7a
24 g_main_context_iterate.isra.24 0x7fe3470b60b8
25 g_main_context_iteration 0x7fe3470b616c
26 QEventDispatcherGlib::processEvents(QFlagsQEventLoop::ProcessEventsFlag) 0x7fe34e6b3a9c
27 QEventLoop::exec(QFlagsQEventLoop::ProcessEventsFlag) 0x7fe34e661c1b
28 QCoreApplication::exec() 0x7fe34e669956
29 main SVGViewMain.cpp 283 0x66a54d