views:

117

answers:

2

I have a QGraphicsScene that has graphics as well as text drawn on it. When I try to print, the graphics are fine, but the text is using a font size defined in points, so scene->render() when I pass it a QPainter initialized with a QPrinter, has VERY large text.

How am I supposed to print a QGraphicsScene that has text on it?

edit:

Here is my current printing code, where scene_ is my custom subclass of QGraphicsScene:

  QPrinter printer(QPrinter::HighResolution);
  QPrintDialog dialog(&printer, this);
  dialog.exec();
  std::cout << printer.resolution() << std::endl;
  QPainter painter(&printer);
  scene_->render(&painter);

The std:cout line doesn't appear to make any difference. The printer still thinks the text is huge, so for each text item only a tiny part of the first letter is printed.

+2  A: 

From the QPrinter docs it sounds like you have to specify font sizes in pixels to get text and graphics to match up. Note that QFont has a setPixelSize method.

Troubadour
That makes the font device dependent. My users may have multiple monitors, and I don't want to calculate a font in pixels for one monitor, then they drag it to another monitor and it looks bad.
David Burson
Or do I need to use point size normally, but when the user prints, iterate through all my text and re-compute the fonts in pixels? Hopefully there's a better way?
David Burson
@David Burson: It will necessarily be device dependent to to work on both a monitor _and_ a printer. Setting a point size and making it device independent means that 72-point text will always be one inch high whether it's on a printed piece of paper or on monitors of varying resolution. So, yes, I think you have to treat the printer as a special case and work out the pixel size.
Troubadour
that makes sense - but is there a better way to handle printing than to iterate through every text object, reset its font to a calculated pixel size, render the scene to the printer, then iterate back through all the text objects and reset their fonts back to the appropriate point size?
David Burson
@David Burson: You can put the code in your re-implementation of `paint` for your text objects. Query the painter's `device()` and if it dynamic casts to a `QPrinter` then use pixels sizes. Alternatively if your graphics and text are very tightly dependent on each others sizes then you may be better using pixel sizes everywhere.
Troubadour
pixel sizes everywhere seems to be the best bet, and is now working for us.
David Burson
+1  A: 

Setting up the QPrinter:

By default, a QPrinter object is initialized to screen resolution (usually 96 DPI) unless you specify QPrinter::HighResolution in the constructor which will then use the resolution of the printer in use.

If you are setting up the QPrinter object using a QPrintDialog then the code should be something like this:

QPrinter printer(QPrinter::HighResolution);
QPrintDialog dialog(&printer, this);
dialog.exec();
std::cout << printer.resolution() << std::endl;

After this, the program should output the DPI of the selected printer. In my case it prints out 600.

If you aren't using the QPrintDialog, you should use the QPrinter constructor as shown above and then call setResolution(DPI) with the known DPI of your printer.

This should result in fonts that are rendered correctly.

Update:

Now that the weekend is here, I finally had time to properly consider this issue :) Although technically correct for setting up a QPrinter, the above solution is not practical for Graphics scenes that include text specified in point sizes. Since all graphic items are specified in pixel coordinates, it only makes sense to specify font sizes in pixels as well to ensure that fonts appear exactly as expected when mixed with other graphic primitives.

There is no need to be concerned about the size of the text on different monitors as the graphics items themselves are not resolution independent. The view can specify scale translations to deal with different resolution and DPI monitors.

When printing, by default, the QPrinter scales to fit the entire scene to the page. Which makes sense since a 100 x 100 square on a 600 DPI printer is goint to be 1/6th of an inch wide on your paper :)

Arnold Spence
I'd like to use QPrintDialog. I tried your solution but it had no effect - I'm new to C++ and Qt and probably missed something. I also added #include <iostream> to get std::cout to compile. My full printing code is now added to my original question - any thoughts?
David Burson
The cout is just there so you can see if the QPrinter picked up the proper DPI setting from the QPrintDialog. What does it print out for you after you click 'print' on the dialog? (you should run your program from the console so you can see the output if your IDE doesn't show it to you.)
Arnold Spence
600 is what it prints out for the printer resolution.
David Burson
That sounds right then. I'll do some experiments this evening and see what results I get. I'll share whatever info I gather, though it may not be as soon as you need to move on :)
Arnold Spence
thanks - I really appreciate it! By the way, in case it makes a difference, my text objects on the scene are a custom subclass of QGraphicsObject, with (among other things) paint reimplemented to allow for drawing text along a curve. Thought I'd mention that in case how the text gets on the scene makes a difference.
David Burson