I am trying to code a text editor from scratch in C++ using Qt/QML. For drawing the text I use a Canvas with a Context2D , which looks roughly like this:
function drawString(text, x, y, font) {
var ctx = getContext("2d");
ctx.font = font;
ctx.fillStyle = "black";
ctx.fillText(qsTr(text), x, y);
ctx.stroke();
}
In order to graphically represent a selected area, I want to invert the selecion, for instance place a black rectangle over an area and make the text white.
For this I will use ctx.globalCompositeOperation = "xor"
So the problem I ran into is: when I draw a text with the function above in black, and then afterwards paint the same text in the same location in white I would expect this canvas to be white again. Instead there is still some kind of outline of the text visible (like there is a shadow).
I already tried switching off all shadow parameters but it didn't solve my problem.
Here is a screenshot so you get a better idea of what it looks like:
Nevermind, I found the problem myself. The antialiasing property was set to true, which caused the effect. By setting it to false the text doesn't look as pretty but the shadow is gone.
Related
I am using following code to print graphics rectangle
var gr = XGraphics.FromPdfPage(1);
Color color = System.Drawing.Color.White;
var brush = new System.Drawing.SolidBrush(color);
gr.FillRectangle(brush, item.Position.X, item.Position.Y, item.Width, item.Height);
But when I execute above code there is border on that rectangle.That rectangle is in following image.
In this image border is showing when I execute above code, But is there any way so I can remove that border?
How does it look when you skip FillRectangle? I think the "border" is already there and your reactangle is just a little too small.
1) How can I wrap text in a QGraphicsTextItem to fit a fixed rectangle, with width and height ?
Right now I am experimenting with creating a text, getting its bounding rectangle, and resizing it to fit the box - but I can't get wrapping.
class TTT: public QGraphicsTextItem {
TTT() {
{
setPlainText("abcd");
qreal x = m_itemSize.width()/boundingRect().width();
qreal y = m_itemSize.height()/boundingRect().height();
scale(x, y);
}
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
// experiment with clip regions
// text gets covered by hole in clip
QRegion r0(boundingRect().toRect());
QRegion r1(QRect(5, 5, 10, 10), QRegion::Ellipse);
QRegion r2 = r0.subtracted(r1);
painter->setClipRegion(r2);
painter->setBrush(Qt::yellow);
painter->drawRect(boundingRect());
QGraphicsTextItem::paint(painter, option, widget);
}
}
What makes wrapping happen, how can I trigger it ?
Right now, as I keep typing, the box is automatically expanding.
2) Is it possible to wrap the text in a QGraphicsItem / QGraphicTextItem subclass in a shape that is not a rectangle ?
(Something like in the image above)
I tried to use clipRegion, see code above, but I guess it is not the right way to go, clipping cuts the text but did not wrap.
Maybe it would... If I could figure out how to wrap text in the first place ?
Qt 4.8
You did not specify Qt version but try:
void QGraphicsTextItem::setTextWidth(qreal width)
Sets the preferred width for the item's text. If the actual text is wider than >the specified width then it will be broken into multiple lines.
If width is set to -1 then the text will not be broken into multiple lines >unless it is enforced through an explicit line break or a new paragraph.
The default value is -1.
In answer to 1) I'd opt not to use the QGraphicsTextItem, but draw the text directly in your QGraphicsItem's paint function using the drawText overloaded function, which takes a QTextOption parameter.
Using this, you can set the WrapMode, for example, with a call to
QTextOption::setWrapMode(QTextOption:: WordWrap)
As for 2) with a non-rectangular shape, I don't think Qt will do this for you.
Doing it yourself you can use QFontMetrics, to work out just how much text would fit in each line, depending upon where it lies within its bounding item.
Alternatively, you could adapt the concept of a text-to-path method.
I have some small graphicsitems on a canvas which need to display some text. When there is a line break, the vertical line spacing is unnecessarily large, which makes the text be drawn outside the graphic items. I have been searching for a way to set the line spacing (or maybe height) on a QGraphicsTextItem but no luck.
I have tried;
setHtml("<div line-height=100%>some text</div>")
etc.
The code where a need to set the inter line apace is:
class GraphicText(QtGui.QGraphicsTextItem):
def __init__(self, text='', font=None, editable=False, text_width = None, **kw):
super(GraphicText, self).__init__(**kw)
if editable:
self.setTextInteractionFlags(QtCore.Qt.TextEditorInteraction)
else:
self.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
if font:
self.setFont(font)
self.setText(text, text_width)
def setText(self, text = '', text_width = None):
cw = self.textWidth()
try:
width = text_width or (cw if cw>0 else False) or self.parentItem().boundingRect().width()-4
except AttributeError:
width = 100
self.setTextWidth(width)
self.setHtml(text)
rect = self.boundingRect()
self.setPos(-rect.width() / 2, -rect.height() / 2) # center
This is Python/PySide, but otherwise the API is pretty much the same as for C++. The HTML is currently passed into the init method as parameter 'text'. The parent of the QGraphicsTextItem is a QGraphicsItem.
Please help, this is really an eyesore.
Cheers, Lars.
This behavior is not reproduced when the line break is caused by <br> in the item's html code. Auto line break using "test1 test2" content and setTextWidth is also working fine. But when the line break is caused by <p></p> tags, the unnecessarily large line height shows up. I assume that this is your case. It can be easily fixed:
item->document()->setDefaultStyleSheet("p { margin: 0; }");
Note that you need to call it before setting item's content. This command doesn't affect current content.
I have a QMessagebox with a custom background image. Since there is some stuff on the top side of the background image I want to see, the text of the messagebox should be lowered. Does anybody know how I can do this? I already tried throwing in some white lines using br, so:
popup.setText("<font size =5 color =white ><br>""<br>""<br>""Are you sure you
want to erase the memory</font> ");
but this screws up the background picture. Is there any way I can move the "box" that contains the text to a lower position?
You could try to get the QMessageBox' layout, get the label which holds your text and increment the labels margin. This probably is a hack and might make your project unportable. Construct your QMessageBox, call hack and then exec the box.
void hack(QMessageBox* pMessageBox)
{
QGridLayout* grid = qobject_cast<QGridLayout*>(pMessageBox->layout());
if (grid)
{
QLabel* label = qobject_cast<QLabel*>((grid->itemAtPosition(0,1))->widget());
if (label)
{
label->setMargin(label->margin()+5); // whatever is suitable
}
}
}
I need to do some emulation of some old DOS or mainframe terminals in Flex. Something like the image below for example.
The different coloured text is easy enough, but the ability to do different background colours, such as the yellow background is beyond the capabilities of the standard Flash text.
I may also need to be able to enter text at certain places and scroll text up the "terminal". Any idea how I'd attack this? Or better still, any existing code/components for this sort of thing?
Use TextField.getCharBoundaries to get a rectangle of the first and last characters in the areas where you want a background. From these rectangles you can construct a rectangle that spans the whole area. Use this to draw the background in a Shape placed behind the text field, or in the parent of the text field.
Update you asked for an example, here is how to get a rectangle from a range of characters:
var firstCharBounds : Rectangle = textField.getCharBoundaries(firstCharIndex);
var lastCharBounds : Rectangle = textField.getCharBoundaries(lastCharIndex);
var rangeBounds : Rectangle = new Rectangle();
rangeBounds.topLeft = firstCharBounds.topLeft;
rangeBounds.bottomRight = lastCharBounds.bottomRight;
If you want to find a rectangle for a whole line you can do this instead:
var charBounds : Rectangle = textField.getCharBoundaries(textField.getLineOffset(lineNumber));
var lineBounds : Rectangle = new Rectangle(0, charBounds.y, textField.width, firstCharBounds.height);
When you have the bounds of the text range you want to paint a background for, you can do this in the updateDisplayList method of the parent of the text field (assuming the text field is positioned at [0, 0] and has white text, and that textRangesWithYellowBackground is an array of rectangles that represent the text ranges that should have yellow backgrounds):
graphics.clear();
// this draws the black background
graphics.beginFill(0x000000);
graphics.drawRect(0, 0, textField.width, textField.height);
graphics.endFill();
// this draws yellow text backgrounds
for each ( var r : Rectangle in textRangesWithYellowBackground )
graphics.beginFill(0xFFFF00);
graphics.drawRect(r.x, r.y, r.width, r.height);
graphics.endFill();
}
The font is fixed width and height, so making a background bitmap dynamically isn't difficult, and is probably the quickest and easiest solution. In fact, if you size it correctly there will only be one stretched pixel per character.
Color the pixel (or pixels) according to the background of the character.
-Adam