Qt QPrinter setPaperSize does not work properly - c++

I am trying to create a Windows application (but will eventually port it to linux also, so cross-compatibility is important if possible) that will take a picture from a webcam and can print without using a printDialog box, but I am having an issue selecting a paper size. I would like the paper size to be set to 4" x 6" which is the A6 format, but when I use setPaperSize(QtPrinter::A6) it seems to default to the letter format. It does not always default to letter with all printers though, it looks like each printer handles the command differently, but most default to letter. I believe this may be an issue with Qt and printer compatibility with the drivers.
My question is: Does anyone know a way to set the printer to 4" by 6" in Qt that should work with all printers?
My code is shown below.
void MainWindow::Print() {
QPainter painter;
QPrinter *printer = new QPrinter(QPrinter::HighResolution);
printer->setPaperSize(QPrinter::A6);
if (!painter.begin(printer)) {
qWarning("Failed to open file");
return;
}
painter.fillRect(QRectF(QPointF(108,118),QPointF(110+352, 120+352)), Qt::black);
painter.fillRect(QRectF(QPointF(109,119),QPointF(109+352, 119+352)), Qt::white);
ui->graphicsView->scene()->render(&painter, QRectF(110,120, 350, 350), QRectF(0,0, ui->graphicsView->scene()->width(), ui->graphicsView->scene()->height()), Qt::IgnoreAspectRatio);
painter.drawText(110, 110, "Test");
painter.end();
}
I have tried the following for resizing the paper
printer->setPaperSize(QPrinter::A6)
printer->setPageSize(QPrinter::A6)
printer->setPaperSize(QSizeF(4.0, 6.0), QPrinter::Inch)
none of those seemed to work. If anyone could help me with this issue I would be very greateful

setPaperSize relies on information received from the printer driver, so to be really printer independant, calculare pageRects yourself.
See the pageRect and the paperRect property together with the fullPage property of QPrinter.
See also my answer to Printing pagerect issues where there is a (wrong) starting example of printing arbitrary print rects and how to fix the code given with the question.

Related

Problem with Keypress simulation on Linux (Ubuntu 18)

I'm making a hobby project that is basically a bot for a very old flash game, the mouse move and click works fine, but all key presses make the operating system lag/stutter and sometimes stop listening to all keyboard inputs, real or fake.
I started using just XLib with XTests but didn't work, so I tried XSendEvent instead of XTests, but all symptoms stayed the same, so the last attempt was with XDO, which gave better results, but still freezes the OS.
this is the current snippet that I'm trying to use to simulate a keypress:
//Constructor
CheatCore::CheatCore() {
xdo_t x = xdo_new(NULL);
Window *list;
xdo_search_t search;
unsigned int nwindows;
memset(&search, 0, sizeof(xdo_search_t));
search.max_depth = -1;
search.require = xdo_search::SEARCH_ANY;
search.searchmask = SEARCH_CLASS | SEARCH_ONLYVISIBLE;
search.winclass = "Chrome";
int id = xdo_search_windows(x, &search, &list, &nwindows);
qDebug() << nwindows;
if(!nwindows){
qDebug() << "Chrome not found";
return;
}
w = list[0];
//I have to call activate twice to really bring it forward, I suspect that its
//because I use a transparent "overlay" that show stats for the cheat and it is set as Aways on top
//(i used Qt to set it to not get any Events)
xdo_activate_window(x,w);
xdo_activate_window(x,w);
}
//there is a function that executes every second to check if a pixel color has changed,
//if so, then the SendKey is called to Reload weapon magazine pressing the "space" key
void CheatCore::SendKey(){
xdo_activate_window(x,w);
xdo_activate_window(x,w);
xdo_send_keysequence_window(x, w, "space", 500);
}
I'm using a transparent overlay to show the bot status, with just some numbers appearing, it is a widget created using Qt that is AlwaysOnTop and the paint event draws the desired information's, it is another object and don't have direct impact in the CheatCore, but this is the window flags used to draw over a transparent window and ignore events.
setWindowFlags(Qt::WindowTransparentForInput | Qt::FramelessWindowHint |
Qt::WindowStaysOnTopHint);
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TranslucentBackground);
setAttribute(Qt::WA_TransparentForMouseEvents);
I didn't manage to understand what could be provoking this weird behavior, could it be the windowing system?
Also, I tried to find a Qt way of simulating mouse/keyboard inputs, but i didn't manage to find any solution to send events to other windows if there is a way possible of achieving this would be great!
The game i'm trying to automate is called "Storm the House"
If interested this is the link to the online repo : link
Can you help me make this work? Thank you!
Context about the setup:
Ubuntu 18.10 using VGA and Nvidia drivers (if it may influence the xserver)
Did you ever try to use xdotool from command line. To use xdotool you need to install package first.
To simualte a key press, you can use.
xdotool key <key>
For example if you want to simulate key press for X you can use this code
xdotool key x
Or any other combination like
xdotool key ctrl+f
Also you can replace key press with another one, for example if you want to replace pressing D with Backspace you can try this one
xdotool key D BackSpace
You can read complete guid online, also you can write script with this tool and use it in many different situations.
Also you can use it for remote connection too.
I hope this helps you with your little problem.
Using evdev is a linux specific option.
It's a simpler solution as you just need to open the correct file and write to it.
Take a look at this similar question to see how to get started.

Made a Text Browser in QT but the Code Acts Like it Doesn't Exist?

I'm pretty new to QT so maybe the answer to this question is simple. I'm making a terminal for our freescale car this year which is just a car that autonomously goes around a track. We're using line-scan cameras which give you a line of data 128 pixels long that you refine into either "white" or "black" (edges of the track) values. Last year the team made this terminal in QT which is used for modifying certain coefficients, stopping the motors, and all kinds of stuff through bluetooth. A text browser was used to display what the line cameras see.
Last year they combined the two cameras to create one image, but we're re configuring them this year, and they will produce two different images of the track. Naturally, I need to make two text browsers, one for each camera. Should simply be a case of copying code and changing some names right? Well apparently not.
I placed the text browser in the window using the design gui, named it, and made its settings match the other browser. I went into the code for the main window c file and adapted the code there. For every reference to the other browser I made sure one was an equal line of code for this one. When I was done and went to build the project, it told me that the browser wasn't a member of 'UI::MainWindow,' and pointed me to the ui_mainwindow.h file. So I went into that header and did the same thing in there. But when I built that, it gave me the error:
...\ui_mainwindow.h:1363: error: C2065: 'tb_camera_out_close' : undeclared identifier
How can that be? There doesn't appear to be any other reference to the other text browser and it works fine. How do I go about declaring this? Shouldn't the gui interface have done it for me when I placed it?
Here's the code from the main window's C file that is involved:
ui->tb_camera_out->setText(msgs_received[1] + '\n' + ui->tb_camera_out->toPlainText());
ui->tb_camera_out_close->setText(msgs_received[2] + '\n' + ui->tb_camera_out_close->toPlainText());
tb_camera_out is the old camera code(I am aware that the toplaintext() part won't work, I'm also attempting to get the text to scroll down instead of up like a track would if you were actually driving but I need to fix this major issue first)
Here's the code from the header that I added:
tb_camera_out = new QTextBrowser(centralWidget);
tb_camera_out->setObjectName(QStringLiteral("tb_camera_out"));
sizePolicy.setHeightForWidth(tb_camera_out->sizePolicy().hasHeightForWidth());
tb_camera_out->setSizePolicy(sizePolicy);
tb_camera_out->setMinimumSize(QSize(450, 0));
tb_camera_out->setMaximumSize(QSize(16777215, 16777215));
tb_camera_out->setStyleSheet(QLatin1String("background-color: rgb(0, 0, 0);\n" "color: rgb(31, 234, 0);"));
gridLayout_4->addWidget(tb_camera_out, 1, 0, 1, 5);
tb_camera_out_close = new QTextBrowser(centralWidget);
tb_camera_out_close->setObjectName(QStringLiteral("tb_camera_out_close"));
sizePolicy.setHeightForWidth(tb_camera_out_close->sizePolicy().hasHeightForWidth());
tb_camera_out_close->setSizePolicy(sizePolicy);
tb_camera_out_close->setMinimumSize(QSize(450, 0));
tb_camera_out_close->setMaximumSize(QSize(16777215, 16777215));
tb_camera_out_close->setStyleSheet(QLatin1String("background-color: rgb(0, 0, 0);\n" "color: rgb(31, 234, 0);"));
Again, the old code is at the top with the references to tb_camera_out. The stuff I added is associated with tb_camera_out_close.
I seem to have solved the problem. Strangely enough, to fix the errors that were showing up I not only had to edit that header, but I then had to delete it and run qmake to restore it. I then had to delete all the past builds to get the thing to even show up when I ran it.

Print the contents of QWebFrame with header and footer

I want to print a QWebView with a header and a footer. I'm using the class QPrintPreviewDialog to preview the print.
I saw how solve this issue the projects phantomjs and wkhtmltopdf but it seems a little excessive the need to include in my project a modified version of WebKit.
Apparentyly printing headers and footers with Qt and Webkit it's an issue not enterely solved:
https://bugs.webkit.org/show_bug.cgi?id=30357
https://bugreports.qt.io/browse/QTBUG-29619
https://wiki.qt.io/Qt_project_org_faq (Question 229)
A priori I don't know how many pages I am going to print. Currently I am subclassing QPrinter and reimplementing the newPage() method. It's an awful hack but nearly works. The issue i'm facing is that everything that it is printed outside the pageRect it is shown like blurred. The watermark effect is only present in the preview not in the printed result, but the low quaility is present always.
There is something i can do to print headers with better quality, without bring all WebKit to my project?.
The difference that I suspect is introducing the problem is that I use QWebView::render instead of QWebView::print. QCustomPrinter has an associated QPainter before printing the header ( the QPainter associated when the content was printed ). Therefore I can't invoke QWebVieww:print when printing the headers because that method tries to associate a new QPainter to QPrinter.
void CustomPrinter::printHeader()
{
QPainter & painter =*this->paintEngine()->painter();
QWebView v;
v.setContent("<html> "
"<body>"
" asdadasdasdasd "
"</body>"
"</html>");
v.setFixedSize(this->pageRect().size());
v.render(&painter,QPoint(0,- 95),QRegion(0,0,this->pageRect().width(),95));
}
EDIT (based on Kuba Ober answer):
Using QTextDocument instead of QWebView solves the quality issue.
void CustomPrinter::printHeader()
{
QPainter * painter =p->paintEngine()->painter();
painter->save();
QTextDocument v;
v.setHtml(QString::fromStdString(_impresion.cabecera()));
QRectF r =this->pageRect();
r.moveTo(0,0);
r.setHeight(95);
painter->translate(0,-95);
v.drawContents(painter,r);
painter->restore();
}
I share a minimun example of what i'm talking about. The CustomPrinter class prints the header.
https://www.dropbox.com/s/2vifzk8rs6scrx5/stackExample.tar.gz?dl=0

Detecting PDF Printing on Mac

I use a QPrintDialog to initialize a QPrinter object like this:
QPrinter printer;
QPrintDialog dlg(&printer);
if (dlg.exec() == QDialog::Accepted)
{
/* Are we printing to PDF? */
}
On Windows, it's easy to detect if the output is going to a file or to a PDF writer. On a Mac, none of the same functions work:
if ((printer.outputFormat() == QPrinter::PdfFormat)
|| (!printer.outputFileName().isEmpty()))
{
qDebug("PDF mode");
}
Looking at a copy of qprintdialog_mac.mm online, in the function QPrintDialogPrivate::closeCarbonPrintPanel(), Qt attempts to detect if the output is redirected to a file. It stores the file name in a member of QMacPrintEnginePrivate. Somehow that name never makes its way to the QPrinter object. I'm not sure where the disconnect is.
So..... how can I tell if the print output is actually going to a file? I'm willing to get platform specific here if it's easy. I have zero Mac programming experience though.
This was a bug in Qt.
In Qt 5.3 the sample code provided will work because of the second condition, the call to QPrinter::outputFileName().
As of Qt 5.14, the outputFileName property of QPrinter is still null, even if "Save as PDF" was selected in the QPrintDialog.
However, when painting to the QPrinter object, the right thing is done.
if "Open with Preview" was selected, the painted contents will open
in preview.
if "Save as PDF" is selected, a file dialog will pop up
if "Send in Mail" is selected, the mail client will open with the PDF
attaced
etc.
Somehow, the QPrinter seems to store all the info from the dialog in an opaque way not accessible through public getters.
The correct way to support all the options from the mac print dialog seems to be:
QPrinter printer;
QPrintDialog dlg(&printer);
if (dlg.exec() == QDialog::Accepted)
{
QPainter painter;
painter.begin(&printer);
// do the painting
painter.end();
}
Unfortunately, it does not seem possible to extract the info out of the QPrinter object in case you like to implement your own printing logic.

Using images in QListWidget, is this possible?

I am using QT to create a chat messenger client. To display the list of online users, I'm using a QListWidget, as created like this:
listWidget = new QListWidget(horizontalLayoutWidget);
listWidget->setObjectName("userList");
QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Expanding);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(listWidget->sizePolicy().hasHeightForWidth());
listWidget->setSizePolicy(sizePolicy1);
listWidget->setMinimumSize(QSize(30, 0));
listWidget->setMaximumSize(QSize(150, 16777215));
listWidget->setBaseSize(QSize(100, 0));
listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
Users are shown by constantly refreshing the list, like this: (Note: There are different channels, with different userlists, so refreshing it is the most efficient thing to do, as far as I know.)
void FMessenger::refreshUserlist()
{
if (currentPanel == 0)
return;
listWidget = this->findChild<QListWidget *>(QString("userList"));
listWidget->clear();
QList<FCharacter*> charList = currentPanel->charList();
QListWidgetItem* charitem = 0;
FCharacter* character;
foreach(character, charList)
{
charitem = new QListWidgetItem(character->name());
// charitem->setIcon(QIcon(":/Images/status.png"));
listWidget->addItem(charitem);
}
}
This has always worked perfectly. The line that I commented out is the one I have problems with: my current goal is to be able to display a user's online status with an image, which represents whether they are busy, away, available, etc. Using setIcon() does absolutely nothing though, apparently; the items still show up as they used to, without icons.
I'm aware that this is probably not the way this function needs to be used, but I have found little documentation about it online, and absolutely no useful examples of implementations. My question is, can anybody help me with fixing this problem?
This is how you may conduct your debugging:
Try the constructor that has both icon and text as arguments.
Try to use that icon in another context to ensure it is displayable (construct a QIcon with same argument and use it elsewhere, e.g. QLabel!).
Use icon() from the QListWidgetItem to receive back the icon and then look at that QIcon.
Create a new QListWidget, change nothing, and ordinarily add some stock items in your MainWidget's constructor. See if the icons show up there.