PDA

View Full Version : Printing with a coordinate system given in millimeters



doberkofler
24th April 2010, 07:53
I was wondering what the best (simple and efficient) way would to for printing in Qt when the given coordinate system is defined in absolute coordinates given in millimeters.
To better explain the problem: I have a definition of what needs to printed specified by different "tokens" (point, line, rectangle, text, etc.) with coordinates (and text sizes) given in millimeters. The positions are relative to the top left corner of a standard A4 page.

wysota
24th April 2010, 09:09
Use QPainter::setWindow() and QPainter::setViewport() to inform Qt about logical and physical coordinates respectively. You can also use GraphicsView with a scene that has dimensions reflecting the logical coordinates that you want to have.

doberkofler
25th April 2010, 10:26
Thank you for the hint. It works just fine except when settings the font size where I'm stuck.
I the following code example the coordinate translation works fine except for the font size that needs to either set in pixel or point.



class Report : public QObject
{
Q_OBJECT

public:
Report(const QString& theTitle, int theNumberOfPages) : itsTitle(theTitle), itsNumberOfPages(theNumberOfPages) {}
void preview();
void printPage(QPainter* thePainter, int thePage);

private slots:
void printDocument(QPrinter* thePrinter);

private:
QString itsTitle;
int itsNumberOfPages;
};

void Report::preview()
{
QPrinter aPrinter(QPrinter::HighResolution);
QPrintPreviewDialog aPreview(&aPrinter, 0);
connect(&aPreview, SIGNAL(paintRequested(QPrinter *)), this, SLOT(printDocument(QPrinter *)));
aPreview.exec();
}

void Report::printDocument(QPrinter* thePrinter)
{
thePrinter->setFromTo(1, itsNumberOfPages);

QString aTitle = QString(tr("Preparing %1")).arg(itsTitle);
QProgressDialog aProgress(aTitle, tr("&Cancel"), 0, itsNumberOfPages, 0);
aProgress.setWindowModality(Qt::ApplicationModal);
aProgress.setWindowTitle(itsTitle);
aProgress.setMinimum(thePrinter->fromPage() - 1);
aProgress.setMaximum(thePrinter->toPage());

// Configure a painter with local coordinate system in 1/10th of a millimeter based on an A4 landscape page
QPainter aPainter;
aPainter.begin(thePrinter);
int aLogicalWidth = 21000;
int aLogicalHeight = 29700;
aPainter.setWindow(0, 0, aLogicalWidth, aLogicalHeight);
int aPhysicalWidth = thePrinter->width();
int aPhysicalHeight = thePrinter->height();
aPainter.setViewport(0, 0, aPhysicalWidth, aPhysicalHeight);

// Print all pages
bool aFirstPage = true;
for (int aPage = thePrinter->fromPage(); aPage <= thePrinter->toPage(); ++aPage)
{
if (!aFirstPage)
thePrinter->newPage();

qApp->processEvents();
if (aProgress.wasCanceled())
break;

// Print page
printPage(&aPainter, aPage);

aProgress.setValue(aPage);
aFirstPage = false;
}

aPainter.end();
}

void Report::printPage(QPainter* thePainter, int thePage)
{
// Set pen
QPen aPen;
aPen.setColor(Qt::black);
aPen.setWidth(0);
aPen.setStyle(Qt::SolidLine);
thePainter->setPen(aPen);

// Set brush
QBrush aBrush;
aBrush.setColor(Qt::black);
aBrush.setStyle(Qt::SolidPattern);
thePainter->setBrush(aBrush);

// Set font
QFont aFont;
aFont.setFamily("Arial");
aFont.setPixelSize(100); // ??? how to set the font size to 1cm ???
aFont.setWeight(QFont::Normal);
aFont.setItalic(false);
thePainter->setFont(aFont);

// Draw line
thePainter->drawLine(QPoint(1000, 1000), QPoint(5000, 5000));

// Print a rectangle
thePainter->drawRect(QRect(8000, 8000, 2000, 2000));

// Print a text
QString aText = QString("%1 on page %2").arg(itsTitle).arg(thePage);
thePainter->drawText(1000, 12000, aText);
}

wysota
25th April 2010, 11:02
If you scale the canvas in milimeters, the font size will also have to be given in milimeters but scaled with a factor matching the one between the window and the viewport (in other words you have to calculate how many "pixels" or "points" fit into one "milimeter").

_Jack_
25th April 2010, 17:38
HI, I have a quite similar problem, I want to print a square 20 * 20 mm and I'm using this code:


QPrinter printer;
printer.setPaperSize(QPrinter::A4);
printer.setOrientation (QPrinter::Portrait);

QPainter painter;
int LogicalWidth = 210;
int LogicalHeight = 297;
painter.setWindow(0, 0,LogicalWidth, LogicalHeight);
int PhysicalWidth = printer.width();
int PhysicalHeight = printer.height();
painter.setViewport(0, 0, PhysicalWidth, PhysicalHeight);
painter.begin(&printer);
painter.drawRect(50,50,20,20);
painter.end();

the square I obtain is quite 5*5 mm , but i expect a square 20 * 20 mm...where is my mistake?
Thankyou in advance.

doberkofler
28th April 2010, 06:09
This is strange as your example looks correct to me. Maybe "wysota" has an idea.

_Jack_
30th April 2010, 14:07
Thanks for reply.
I resolved my problem in this way: taking in account printer resolution (hoping this is a general solution) :

QTransform TPiXEL = QTransform::fromScale(
painter.device()->physicalDpiX() / 25.400,
painter.device()->physicalDpiY() / 25.400);
painter.setWorldTransform(TPiXEL, false);

Thanks.

doberkofler
5th May 2010, 07:09
Are you now using setWorldTransform together with setWindow/setViewport or instead of the method suggested by wysota?