PDA

View Full Version : [QT4] QThread and printing a QList<QPixmap>



KShots
24th April 2006, 20:53
Hello all...

I've got a program where I'm trying to print a list of pixmaps in a separate thread, so the user can continue working while the app prints off a copy of the work.

Structurally, I have this:

1. main thread brings up print dialog to set up printer options, and stores them inside the print thread

2. main thread takes snapshots of selected dialogs, stores them in a QList <QPixmap> structure contained in the print thread (before the print thread starts).

3. main thread starts print thread and goes on with life

4. print thread re-scales each image in the list to the paper size (using the smooth scaling option - time consuming)

5. print thread prints each pixmap, one to a page

6. print thread exits, emits a finished() signal. Main thread sees this and deletes the print thread. If another print request comes up before this time, main thread will block until print thread finishes and becomes deleted, then create a new one.

Sounds pretty straight-forward to me... but apparently not.

I'm getting weird X window errors and out-of-memory errors when I do this. I think I may have a solution for the out-of-memory errors (kind of) if I can get the setStackSize() to work (complains about an invalid argument:confused: ). It works fine if I call the run() function instead of the start() function of the thread (forcing it to work on a single thread), but I'm getting the following:
Xlib: unexpected async reply (sequence 0x18d32)!
Xlib: sequence lost (0x200e6 > 0x196d4) in reply type 0xe6!
In file image/qpixmap_x11.cpp, line 709: Out of memory
When I use setStackSize(100000000) (100M), I get the following instead:
X Error: BadRequest (invalid request code or no such operation) 1
Extension: 239 (Uknown extension)
Minor opcode: 0 (Unknown request)
Resource id: 0x20024beand it scrolls on - 1 for each item printed, I think.

Also, when I use the setStackSize function intelligently:
QThread::start: thread stack size error: Invalid argumentI'm a little confused on how to best proceed.

Below is the code from the thread (header):
class threadPrint : public QThread
{
Q_OBJECT
public:
threadPrint(QObject * parent = 0);
virtual ~threadPrint();

void run();

QList <QPixmap> pixlist;
QPrinter printer;
};... and the source for the thread (The constructor / destructor are empty):
void threadPrint::run()
{
QPainter painter;
painter.begin(&printer);
for(QList<QPixmap>::iterator i = pixlist.begin(); i != pixlist.end(); ++i)
{
if(i != pixlist.begin())
{
printer.newPage();
}
(*i) = (*i).scaled(printer.pageRect().width(), printer.pageRect().height(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
painter.drawPixmap(0, 0, (*i));
}
painter.end();
}Pretty simple stuff so far... and the print slot from the main thread:
void formMainApp::menuFilePrint()
{
PrintThread = new threadPrint;
PrintThread->printer.setColorMode(QPrinter::GrayScale);
PrintThread->printer.setOrientation(QPrinter::Landscape);
QPrintDialog qp(&PrintThread->printer, this);
if(qp.exec() == QDialog::Accepted)
{
QModelIndexList MIL = ui.treeViewSQLList->selectionModel()->selectedIndexes();
for(QList<QModelIndex>::const_iterator i = MIL.begin(); i != MIL.end(); ++i)
{
if(!(*i).column()) //Only care about the rows selected, not the columns (entire rows selected)
{
myForm * T = myTreeModel->findForm(*i); //myForm is the dialog to take a snapshot of, obtained from my model
T->show(); //Qt has a deficiency where it cannot take a snapshot of a form that is not being displayed
QPixmap pixmap = QPixmap::grabWidget(T, T->rect());
T->close();
PrintThread->pixlist.append(pixmap);
}
}
PrintThread->setStackSize(sizeof(threadPrint) + sizeof(QPixmap) * (PrintThread->pixlist.count() + 1));
PrintThread->start();
}
}... and theoretically, it should go on its merry way and print. But looking above, it does all sorts of funky stuff. Any ideas? Do I have some basic concept horribly disfigured?

jacek
24th April 2006, 21:10
QPixmaps are stored on the X Server, so you can't use them in a non-GUI thread. Use QImages instead.

jpn
24th April 2006, 21:12
Without even reading the whole post of yours, I'd like to remind you about the fact that QPixmap is not thread-safe, QImage is.

KShots
24th April 2006, 21:44
Yeah, you're both right. Using QImage caused it to work right away. I didn't need to mess with the stack size either, so I took that line out. Thanks!