Painting in a QTextEdit without affecting the text - qt

I am trying to paint some lines in a QTextEdit but when paintEvent it is called the whole QTextEdit text clears, the lines are drawn, no further text input possible. If I scroll, the drawn lines act very weird, somehow multiply on horizontal or vertical. I want to paint on the QTextEdit w/o affecting it's text and the painted stuff to act normal when scrolling, to keep its coordinates.
Here is the code:
class TextEdit(QTextEdit):
def __init__(self, parent = None):
super(TextEdit, self).__init__(parent)
self.setViewportMargins(10, 0, 0, 0)
def paintEvent(self, event):
painter = QPainter(self.viewport())
painter.drawLine(10, 10, 200, 10)

Add this to the bottom of your paintEvent method:
super(TextEdit, self).paintEvent(event)

Related

How to draw a QPixmap at pos(0, 0) including margin/padding sizes

Inside SidebarButton.paintEvent(), I want to draw a pixmap at position x=0, y=0. When margin:0px is set, this works fine. But if I increase for example margin-top to 30px, drawPixmap(0, 0, ...) paints inside the margin. I've expected that if I set a top margin, drawPixmap(0, 0, ...) starts at (0, 30).
So my question is: how can I draw at the correct position? A simple solution would be drawPixmap(0, getTopMargin() + getTopPadding(), ...) But I can't find any function which gives me the css value for margin-top and others.
BaseButton is derived from QPushButton:
class SidebarButton(BaseButton):
def __init__(self, parent):
super().__init__(parent)
def paintEvent(self, e):
super().paintEvent(e)
p = QPainter(self)
if self._bgimage is not None:
pix = self.prepareIcon()
# p.setRenderHint(QPainter.HighQualityAntialiasing);
p.drawPixmap(0, 0,
pix.scaled(QSize(self.width(), self.width()) / 1.8,
Qt.IgnoreAspectRatio,
Qt.SmoothTransformation))
Edit:
Accessing padding from stylesheet in QT this recommends to use contentsRect() to get the content rectangle. But contentsRect().top() always returns 0 but I think it should return 30. The box model is supported by QPushButton, btw.

Subclassed QFrame not adjusting to it's layout

I'm trying to include a horizontal frame containing a label inside a vertical frame, but even though the label is displayed it's not in the right position and it's limited to a size of a standard QLabel
This is the main class:
class Launcher(QMainWindow):
def __init__(self):
super().__init__()
self.setFrame() #sets up window's geometry, works fine
self.setContent()
self.show()
def setContent(self):
layout = QBoxLayout(QBoxLayout.TopToBottom)
layout.addWidget(widgets.Logo(self), 0, Qt.AlignTop)
self.setLayout(layout)
And this is the imported class from a "widgets" module
class Logo(QFrame):
def __init__(self, parent):
super().__init__(parent)
layout = QBoxLayout(QBoxLayout.LeftToRight)
text = QLabel("PyTitle", self)
text.setAlignment(Qt.AlignCenter)
text.setFont(QFont("impact", 48))
layout.addWidget(text, 0, Qt.AlignCenter)
self.setLayout(layout)
self.show()
The result is this:
If I forcefully resize both QLabel AND QFrame, it's visible, but still in the top-left.
You must not set a layout on a QMainWindow, because it already has one built in (to handle dock-widgets, the menu-bar, status-bar, etc).
Instead, set a central-widget, and add all the widgets and layouts to that:
class Launcher(QMainWindow):
...
def setContent(self):
widget = widgets.Logo(self)
self.setCentralWidget(widget)
(PS: you only need to call show() on the top-level window - for all other child widgets, it's redundant).

Make QPainter paint on top of a content which is inside a QScrollArea and has been scrolled, in the correct position

I'm doing something cool with a custom QWebView, basically I paint a rectangle over the element which is under the mouse pointer, see:
However, if I scroll down and move the pointer again, it draws the rect on the wrong area. In the next screenshot the mouse is over the which contains the search results, the top of the rectangle and the top of the QWebView have a big gap:
What I did to insert this bug was simply calculating the position of the rect taking into account the horizontal and vertical scroll positions, I did this wrong calculation because the rect wasn't correctly positioned in regard to the content if I scrolled it. In both cases I have a rect painted in the wrong position if any scroll occurs.
So far, this is the code I have at the moment:
#!/usr/bin/env python2
# coding: utf-8
# VENI, SANCTE SPIRITUS
from PySide.QtWebKit import QWebView
from PySide import QtCore, QtGui
class CustomQWebView(QWebView):
def __init__(self, *args, **kwargs):
""" Init the custom class
"""
super(CustomQWebView, self).__init__(*args, **kwargs)
self.currentframe = None
self.lastelement = None
self.lastelementboundingrect = None
self.loadFinished.connect(self.setframeafterloadfinished)
# default test pen
self.defaultpen = QtGui.QPen(QtCore.Qt.blue)
self.defaultpen.setWidth(3)
#QtCore.Slot(QtGui.QMouseEvent)
def mouseMoveEvent(self, event):
super(CustomQWebView, self).mouseMoveEvent(event)
if self.currentframe:
hittestresult = self.currentframe.hitTestContent(event.pos())
element = hittestresult.element()
if self.lastelement != element:
self.lastelement = element
self.lastelementboundingrect = hittestresult.boundingRect()
self.update()
#QtCore.Slot(QtGui.QPaintEvent)
def paintEvent(self, event):
# draw the content first
super(CustomQWebView, self).paintEvent(event)
# then the rectangle
if self.lastelementboundingrect:
painter = QtGui.QPainter(self)
painter.setPen(self.defaultpen)
# This rectangles takes into account any offset of the scroll bar
# so the rectangle can be drawn correctly
rect = QtCore.QRect()
rect.setRect(self.lastelementboundingrect.x() +
self.currentframe.scrollPosition().x(),
self.lastelementboundingrect.y() +
self.currentframe.scrollPosition().y(),
self.lastelementboundingrect.width(),
self.lastelementboundingrect.height())
# painter.drawRect(QtCore.QRectF(self.lastelementcurrectrect))
painter.fillRect(
QtCore.QRectF(rect), QtGui.QColor(255, 165, 0, 128))
def setframeafterloadfinished(self):
self.currentframe = self.page().mainFrame()
How can I correctly solve this positioning problem?
P.S.: Yes, the pointer don't appears in the screenshots because scrot cannot capture it, I did not realize before uploading the screenshots. Sorry.
I think you need to subtract the x/y components of page()->mainFrame()->scrollPosition() from your rect's x/y components.
This property holds the position the frame is currently scrolled to.

How to draw over QLabel in Qt

I have to create one screen in Qt in which I have to show a remote having lots of buttons in it and when user clicks some button on actual remote, corresponding button in the image get highlighted. So what I have done is, I have used QLabel and set the remote image as background image and then I have put small rectangular label for each button and filled them with semi transparent color and when user click button in actual remote label color changes, but by using this method lot of labels are getting used making code looking inefficient, so I was thinking of drawing on QLabel (which has a remote as background image) over buttons.
Can anybody suggest me, which API of Qt should I use, and how to follow up on this?
I believe QGraphics is the correct route for a completely custom graphical interface, but if you want to try something that doesn't require you to change too much of your existing approach, you can do a widget with a custom paint event:
This is written in PyQt but you can easily translate to Qt
from PyQt4 import QtCore, QtGui
class LabelButton(QtGui.QWidget):
clicked = QtCore.pyqtSignal()
def __init__(self, labelStr, pixStr, parent=None):
super(LabelButton, self).__init__(parent)
self.label = labelStr
self.pix = QtGui.QPixmap(pixStr)
def paintEvent(self, event):
super(LabelButton, self).paintEvent(event)
rect = event.rect()
painter = QtGui.QPainter(self)
painter.drawPixmap(rect, self.pix)
pos = (rect.bottomLeft()+rect.bottomRight()) / 2
pos.setY(pos.y()-10)
painter.drawText(pos, self.label)
painter.end()
def mousePressEvent(self, event):
event.accept()
self.clicked.emit()
def handleClick():
print "CLICK"
if __name__ == "__main__":
app = QtGui.QApplication([])
widget = LabelButton("A Text Label", "myImage.png")
widget.resize(600,400)
widget.show()
widget.raise_()
widget.clicked.connect(handleClick)
app.exec_()
This is a rough example. You can get more fine tuned with the drawing of the text. This widget takes a label string, and a picture path, and will paint the picture as the background, and the text as a label. You can do any number of things with this custom widget in both the paint event, and with custom signals and events.
I have used this code to Draw over Image in Label:
Image is loaded in Ui and the Code is as follows In paintevent
void ColorTab::paintEvent(QPaintEvent *e){
ui->lbl_capture_img->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
ui->Lbl_color_tab_WG->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
Cap_Image = QImage(ui->lbl_capture_img->pixmap()->toImage());
Lbl_Image = QImage(ui->Lbl_color_tab_WG->pixmap()->toImage());
QPainter painter_Lbl(&Lbl_Image);
QPainter painter_Cap(&Cap_Image);
QPen pen(Qt::white, 5, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin);
painter_Lbl.setPen(pen);
painter_Cap.setPen(pen);
painter_Lbl.drawPolygon(blinkRect_Lbl);
painter_Cap.drawPolygon(blinkRect_Cap);
ui->lbl_capture_img->setPixmap(QPixmap::fromImage(Cap_Image));
ui->Lbl_color_tab_WG->setPixmap(QPixmap::fromImage(Lbl_Image));
painter_Cap.end();
painter_Lbl.end();
}

custom paint() not working with QLayout.setSpacing()

I am struggling to understand something seemingly simple:
I have a custom widget subclassing from QPushButton, multiple instances of which I am laying out in a QGridLayout(). The moment I add a paint() function and draw a background color to fill the button's rect() the layout's spacing does not seem to have an effect anymore.
Here is a screen shot to show what I mean:
This shows default QPushButtons that obey the layout's spacing and my custom "buttons" that don't.
I'm sure I just need to (re)implement something in my CustomButton but can't find what it is. I tried setting contentMargins to no avail.
What am I missing? Maybe I need to not fill self.rect() but something else?
Here is the example code that produces above screen shot:
import sys
from PySide.QtGui import *
from PySide.QtCore import *
class CustomButton(QPushButton):
def __init__(self, tool, icon=None, parent=None):
super(CustomButton, self).__init__(parent)
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.setMinimumWidth(200)
self.frameGeometry()
def paintEvent(self, event):
painter = QPainter(self)
bgColor = QColor(60, 60, 60)
painter.fillRect(self.rect(), bgColor)
app = QApplication(sys.argv)
mainWindow = QWidget()
grid = QGridLayout()
grid.setSpacing(10)
mainWindow.setLayout(grid)
for i in xrange(4):
btn1 = CustomButton('A')
btn2 = QPushButton('B')
grid.addWidget(btn1, 0, i)
grid.addWidget(btn2, 1, i)
mainWindow.show()
sys.exit(app.exec_())
so a solution seems to be to manually adjust self.rect() to be a bit smaller, though I don't understand why this is necessary as I thought that's what the layout's spacing is for:
def paintEvent(self, event):
rect = self.rect()
rect.adjust(5,5,-5,-5)
painter = QPainter(self)
bgColor = QColor(60, 60, 60)
painter.fillRect(rect, bgColor)
This will give me the spacing I need. If anybody can shed light on whether this is a bug or a feature I'd be quite grateful.

Resources