So i'm using QT 5.15.2 and what i'm trying to do here is print ot PDF the content of a QTableView into a PDF File here's my code
void ManageTeachers::on_print_clicked() {
QPdfWriter pdf("C:");
QPainter painter(&pdf);
int i = 4000;
painter.setPen(Qt::blue);
painter.setFont(QFont("Arial", 30));
painter.drawText(1100,1200,"List of teachers");
painter.setPen(Qt::black);
painter.setFont(QFont("Arial", 15));
painter.drawRect(100,100,7300,2600);
painter.drawRect(0,3000,9600,500);
painter.setFont(QFont("Arial", 9));
painter.drawText(200,3300,"CIN");
painter.drawText(1300,3300,"First name");
painter.drawText(2100,3300,"last name");
painter.drawText(3200,3300,"phone");
painter.drawText(5300,3300,"email");
painter.drawText(5300,3300,"salary");
QSqlQuery query;
query.prepare("select * from teacher");
query.exec();
while (query.next())
{
painter.drawText(200,i,query.value(0).toString());
painter.drawText(1300,i,query.value(1).toString());
painter.drawText(2200,i,query.value(2).toString());
painter.drawText(3200,i,query.value(3).toString());
painter.drawText(4500,i,query.value(4).toString());
i = i + 500;
}
int reponse = QMessageBox::question(this, "Génerer PDF", "<PDF Enregistré>...Vous Voulez Affichez Le PDF ?", QMessageBox::Yes | QMessageBox::No);
if (reponse == QMessageBox::Yes)
{
painter.end();
}
if (reponse == QMessageBox::No)
{
painter.end();
} }
The problem is that in the console i get these errors
QPainter::begin(): Returned false
QPainter::setPen: Painter not active
QPainter::setFont: Painter not active
QPainter::setPen: Painter not active
QPainter::setFont: Painter not active
QPainter::drawRects: Painter not active
QPainter::drawRects: Painter not active
QPainter::setFont: Painter not active
QPainter::end: Painter not active, aborted
Any help ? i added the QT+= printsupport multimedia
QPdfWriter pdf("C:");
QPainter painter(&pdf);
This is very suspect. If you consult the documentation for QPdfWriter it notes that the first parameter should be a filename. "C:" is not a filename. You need to pass the name of the file you want to write to, something like:
QString filename("C:/my_file.pdf");
QPdfWriter pdf(filename);
QPainter painter(&pdf);
Related
I'm using Qt6.1 and I want send my widget's pixmap when it painted.
I have similar code:
void MyWidget::paintEvent(QPaintEvent*)
{
// static bool callGrab = true;
// m_callGrab initialize with true
if (m_callGrab)
{
m_callGrab = false;
auto pixmap = grab();
m_callGrab = true;
emit widgetRepainted(pixmap);
QPainter painter(this);
painter.drawPixmap(0, 0, pixmap);
painter.end();
return;
}
QPainter painter(this);
...
painter.end();
}
I know call grab() in paintEvent() will cause recursive so I use a variable to prevent it.
it works well, but I get "QWidget::repaint: Recursive repaint detected" in console. It's too lot and scrolls my debug information up.
I have tried add DEFINES += QT_NO_WARNING_OUTPUT in my .pro file but it doesn't work.
I want to know whether can disable print the message in console.
I can not print to paper for some reasone. So I have a functional printer. And I use the folowing code to print a qDialog and a few pictures out:
QPrinter printer;
QPainter painter;
painter.begin(&printer);
double xscale = printer.width() / double(window->width());
double yscale = printer.height() / double(window->height());
double scale = qMin(xscale, yscale);
painter.scale(scale, scale);
QPrintDialog printDialog(&printer, this);
if (printDialog.exec() == QDialog::Accepted) {
bool skip = true;
if(ui->generalInfos->isChecked()) {
//window is a QDialog I want to print out
window->render(&painter);
skip = false;
}
QList<Document *> docs;
if(worker) {
//a list with path to pictures
docs = worker->getDocuments();
}
for(auto document : docs) {
if(ui->Documents->isChecked(document->getID())) {
for(auto scan : document->getScans()) {
if(!skip) {
printer.newPage();
}
else {
skip = false;
}
painter.resetTransform();
const QImage image(scan);
const QPoint imageCoordinates(0,0);
xscale = printer.width() / double(image.width());
yscale = printer.height() / double(image.height());
scale = qMin(xscale, yscale);
painter.scale(scale, scale);
painter.drawImage(imageCoordinates,image);
}
}
}
}
painter.end();
and it doesn't work. Nothing is printed and Qt trows an error:
QWin32PrintEngine::newPage: EndPage failed (The parameter is incorrect.)
QWin32PrintEngine::end: EndPage failed (0x31210cf7) (The parameter is incorrect.)
can someone please help me?
If you simplify your code, you will probably find the solution.
So lets start with selecting the printer, then (afterwards!) start painting to the printer:
QPrinter printer;
QPrintDialog printDialog(&printer, this);
if (printDialog.exec() == QDialog::Accepted)
{
QPainter painter;
painter.begin(&printer);
window->render(&painter);
painter.end();
}
If this works, add more of your old code to the sketch above.
If it doesn't work, something else in your program or your environment (selected printer?) is wrong, so you need to extend your bug hunt beyond what you showed us here.
I load all text files from my folder to the MainMenu in my Qt application.
void MainWindow::loadFilesToMainMenu() {
QString pathToDir("/myfiles");
QDirIterator it(pathToDir, QStringList() << "*.txt", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()) {
QString curPathName = it.next();
QStringList fileSegments = curPathName.split('/');
QString curFileName = fileSegments.at(fileSegments.size() - 1);
QAction* action = new QAction(tr(curFileName.toStdString().c_str()), this);
action->setStatusTip(tr(curPathName.toStdString().c_str()));
ui->menuFileList->addAction(action);
// if new style selected?
connect(action, SIGNAL(triggered()), this, SLOT(onLoadFile()));
}
}
There I create QActions for all files in my folder 'myfiles' and I connect these each of these ations to the SLOT onLoadfile():
void MainWindow::onLoadFile() {
QAction *action = qobject_cast<QAction *>(sender());
if (action)
{
qDebug() << " onLoadFile " << action->data().toString();
}
}
So each time I select one of those files in my MainMenu, this SLOt is triggered, but my debug message says:
onLoadFile ""
When I for instance select /myfiles/file1.txt
onLoadFile "/myfiles/file1.txt"
Wham am I missing? Thanx in advance
The answer from #m.s. solves my question very well...
You should use QAction::setData() before trying to read the data – m.s
QSystemTrayIcon has a function :
void showMessage(const QString &title, const QString &msg,
MessageIcon icon = Information, int msecs = 10000);
is there a way to change it to custom icon , for example like this -
void showIconMessage(const QString &title, const QString &msg,
QIcon icon = QIcon(), int msecs = 10000);
without modifying the Qt sources
I know that showMessage (d is instance of QSystemTrayIconPrivate and is called with Q_D(QSystemTrayIcon) macro)
void QSystemTrayIcon::showMessage(const QString& title, const QString& msg,
QSystemTrayIcon::MessageIcon icon, int msecs)
{
Q_D(QSystemTrayIcon);
if (d->visible)
d->showMessage_sys(title, msg, icon, msecs);
}
calls showMessage_sys from QSystemTrayIconPrivate where in turn all the magic with icon happens:
void QSystemTrayIconPrivate::showMessage_sys(const QString &message,
const QString &title,
QSystemTrayIcon::MessageIcon icon,
int msecs)
{
if (!qpa_sys)
return;
QIcon notificationIcon;
switch (icon) {
case QSystemTrayIcon::Information:
notificationIcon = QApplication::style()- >standardIcon(QStyle::SP_MessageBoxInformation);
break;
case QSystemTrayIcon::Warning:
notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning);
break;
case QSystemTrayIcon::Critical:
notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical);
break;
default:
break;
}
qpa_sys->showMessage(message, title, notificationIcon,
static_cast<QPlatformSystemTrayIcon::MessageIcon>(icon), msecs);
}
Now, it seems, that I need to re-implement these two functions in two classes and i'm ready to go, but.. It seems that QSystemTrayIcon is closely tied to QSystemTrayIconPrivate. Instance of QSystemTrayIconPrivate is created only in QSystemTrayIcon constructor (which I can't really change if I plan to create classes that inherit both QSystemTrayIcon and QSystemTrayIconPrivate and re-implement showMessage functions):
QSystemTrayIcon::QSystemTrayIcon(QObject *parent)
: QObject(*new QSystemTrayIconPrivate(), parent)
{
}
QSystemTrayIcon::QSystemTrayIcon(const QIcon &icon, QObject *parent)
: QObject(*new QSystemTrayIconPrivate(), parent)
{
setIcon(icon);
}
So is there anything I am missing? Or is there another way to simply show notification message with custom icon?
What you could try (not sure if it will work for system tray) is do the same as described in this answer and override the SP_MessageBoxWarning / SP_MessageBoxCritical / SP_MessageBoxInformation icons, but as I said I'm not sure if the system tray just uses a downscaled version of the message box icons or if the system tray icons are separate. In the case of the latter, I guess you will have to patch QT sources, maybe add a new item to the QSystemTrayIcon and patch the switch to call some function provided by you to return the needed icon. Something like:
void QSystemTrayIconPrivate::showMessage_sys(const QString &message,
const QString &title,
QSystemTrayIcon::MessageIcon icon,
int msecs)
{
if (!qpa_sys)
return;
QIcon notificationIcon;
switch (icon) {
case QSystemTrayIcon::Information:
notificationIcon = QApplication::style()- >standardIcon(QStyle::SP_MessageBoxInformation);
break;
case QSystemTrayIcon::Warning:
notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning);
break;
case QSystemTrayIcon::Critical:
notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical);
break;
case QSystemTrayIcon::Custom:
// Call a function that will fetch the needed icon and assign it to notificationIcon
break;
default:
break;
}
qpa_sys->showMessage(message, title, notificationIcon,
static_cast<QPlatformSystemTrayIcon::MessageIcon>(icon), msecs);
}
To warn before closing a window that inherits from QMainWindow, I reimplemented its closeEvent, which works fine when I emit close() manually. However, clicking the "x" button does not trigger this; it just exits.
It does emit aboutToQuit() for the application, which I can use to "recover" the window after it already closes. But I want to the warning to precede the initial closing.
I'm not sure where the issue is. The window is top-level and there are no running threads. Have I misunderstood what signal is actually connected to the button click...? It is close(), right?
In your mainwindow class header( the closeEvent must be virtual ):
public:
/*!
* \brief closeEvent
* \param event
*/
virtual void closeEvent ( QCloseEvent * event );
Then in the cpp
void MainWindow::closeEvent( QCloseEvent *event )
{
//! Ignore the event by default.. otherwise the window will be closed always.
event->ignore();
if(!EntitiesSaverObserver::Instance()->isAllSaved())
{
QMessageBox msgBox;
msgBox.setWindowIcon(QIcon(":/Resources/Icons/warning.png"));
msgBox.setIconPixmap(QPixmap(":/Resources/Icons/warning.png"));
QString strToShow = QString("Some Entities has been created or modified...");
msgBox.setText(strToShow);
msgBox.setInformativeText("Do you want to save your changes?");
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
switch (ret) {
case QMessageBox::Save:
{
// Save was clicked
qDebug() << "SAVE";
//! Do your stuff here
// ....
event->accept();
break;
}
case QMessageBox::Discard:
{
// Don't Save was clicked
qDebug() << "DISCARD";
event->accept();
break;
}
case QMessageBox::Cancel:
{
// Cancel was clicked
qDebug() << "CANCEL";
break;
}
default:
// should never be reached
break;
}
} else {
event->accept(); // Do not need to save nothing... accept the event and close the app
}
}
Moreover, if you want to put a button in your toolbar as a QAction, you could connect the signal and then:
void MainWindow::on_actionExit_triggered()
{
close();
}
This would call the close event of your main window. I hope this helps you.
just create a signal-slot QObject::connect(yourButton, SIGNAL(clicked()), this, SLOT(close()));