eric
eric

Reputation: 8019

Painting on a widget that contains a QGridLayout in PySide/PyQt

I am making a custom QWidget in which I have a QGridLayout, and draw a rectangle on a particular element in the grid. I also manually draw lines to delineate the location of the grid elements (with QPainter.DrawLines).

After drawing the lines, I then paint the rectangle within one of the grid elements, with its location specified using the QGridLayout coordinate system .

The problem is, the rectangle does not stay confined to its grid element. For instance, in the example below, the blue rectangle and black grid lines get out of alignment, so I end up with a blue box floating around in space.

I have not found explicit discussion of this issue via Google or SO.

Edit:

Note as pointed out in the accepted answer, the mistake was using grid coordinates to draw on the grid, when I should have been using point coordinates (i.e., column, row). That is, the mistake in the code below is that the element in the grid has its x- and y- coordinates reversed.


from PySide import QtGui, QtCore

class HighlightSquare(QtGui.QWidget):
    def __init__(self, parent = None):
        QtGui.QWidget.__init__(self, parent=None)
        self.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,
                                       QtGui.QSizePolicy.Expanding))                  
        self.setMinimumSize(self.minimumSizeHint()) 
        layout = QtGui.QGridLayout()
        layout.addItem(QtGui.QSpacerItem(10,10), 0, 0)
        layout.addItem(QtGui.QSpacerItem(10,10), 0, 1)
        layout.addItem(QtGui.QSpacerItem(10,10), 1, 0)
        layout.addItem(QtGui.QSpacerItem(10,10), 1, 1)       
        self.setLayout(layout)
        self.resize(150, 150)
        self.update()

    def paintEvent(self, event = None):
        painter = QtGui.QPainter(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        winHeight=self.size().height(); heightStep=winHeight/2
        winWidth=self.size().width(); widthStep=winWidth/2

        #Draw lines
        painter.setPen(QtCore.Qt.black)
        for i in range(4):
            #vertical lines
            painter.drawLine(QtCore.QPoint(i*widthStep,0), QtCore.QPoint(i*widthStep, winHeight))
            #horizontal lines
            painter.drawLine(QtCore.QPoint(0,heightStep*i), QtCore.QPoint(winWidth, heightStep*i))

        #Draw blue outline around box 1,1
        highlightCoordinate=(1,1)
        pen=QtGui.QPen(QtCore.Qt.blue, 3)        
        painter.setPen(pen)
        coordHighlight=[QtCore.QPoint(highlightCoordinate[1]*heightStep, highlightCoordinate[0]*widthStep),\
                        QtCore.QPoint(highlightCoordinate[1]*heightStep, (highlightCoordinate[0]+1)*widthStep),\
                        QtCore.QPoint((highlightCoordinate[1]+1)*heightStep, (highlightCoordinate[0]+1)*widthStep),\
                        QtCore.QPoint((highlightCoordinate[1]+1)*heightStep, highlightCoordinate[0]*widthStep),\
                        QtCore.QPoint(highlightCoordinate[1]*heightStep, highlightCoordinate[0]*widthStep)]
        #print coordHighlight
        painter.drawPolyline(coordHighlight)

    def minimumSizeHint(self):
        return QtCore.QSize(120,120)


if __name__=="__main__":
    import sys
    app=QtGui.QApplication(sys.argv)
    myLight = HighlightSquare()
    myLight.show()
    sys.exit(app.exec_())

Upvotes: 0

Views: 2853

Answers (1)

Bandhit Suksiri
Bandhit Suksiri

Reputation: 3450

Have you read the definition of the constructor of class QtCore.QPoint? At method QPoint.__init__ (self, int xpos, int ypos) your code is reversed (ypos, xpos). I fixed it.

import sys
from PyQt4 import QtGui, QtCore

class QHighlightSquareWidget (QtGui.QWidget):
    def __init__ (self, parent = None):
        QtGui.QWidget.__init__(self, parent = None)
        self.setSizePolicy (
            QtGui.QSizePolicy (
                QtGui.QSizePolicy.Expanding,
                QtGui.QSizePolicy.Expanding))
        self.setMinimumSize(self.minimumSizeHint())
        allQGridLayout = QtGui.QGridLayout()
        allQGridLayout.addItem(QtGui.QSpacerItem(10,10), 0, 0)
        allQGridLayout.addItem(QtGui.QSpacerItem(10,10), 0, 1)
        allQGridLayout.addItem(QtGui.QSpacerItem(10,10), 1, 0)
        allQGridLayout.addItem(QtGui.QSpacerItem(10,10), 1, 1)       
        self.setLayout(allQGridLayout)
        self.resize(150, 150)
        self.update()

    def paintEvent (self, eventQPaintEvent):
        myQPainter = QtGui.QPainter(self)
        myQPainter.setRenderHint(QtGui.QPainter.Antialiasing)
        winHeight = self.size().height()
        heightStep = winHeight / 2
        winWidth  = self.size().width()
        widthStep = winWidth / 2

        myQPainter.setPen(QtCore.Qt.black)
        for i in range(4):
            myQPainter.drawLine(QtCore.QPoint(i * widthStep, 0             ), QtCore.QPoint(i * widthStep, winHeight     ))
            myQPainter.drawLine(QtCore.QPoint(0,             heightStep * i), QtCore.QPoint(winWidth,      heightStep * i))

        highlightCoordinate = (1, 1)
        myQPen = QtGui.QPen(QtCore.Qt.blue, 3)        
        myQPainter.setPen(myQPen)
        coordHighlight = [
            QtCore.QPoint( highlightCoordinate[0]      * widthStep,  highlightCoordinate[1]      * heightStep),
            QtCore.QPoint((highlightCoordinate[0] + 1) * widthStep,  highlightCoordinate[1]      * heightStep),
            QtCore.QPoint((highlightCoordinate[0] + 1) * widthStep, (highlightCoordinate[1] + 1) * heightStep),
            QtCore.QPoint( highlightCoordinate[0]      * widthStep, (highlightCoordinate[1] + 1) * heightStep),
            QtCore.QPoint( highlightCoordinate[0]      * widthStep,  highlightCoordinate[1]      * heightStep)]
        myQPainter.drawPolyline(*coordHighlight)

    def minimumSizeHint (self):
        return QtCore.QSize(120, 120)

if __name__=="__main__":
    myQApplication = QtGui.QApplication(sys.argv)
    myQHighlightSquareWidget = QHighlightSquareWidget()
    myQHighlightSquareWidget.show()
    sys.exit(myQApplication.exec_())

Upvotes: 1

Related Questions