PyQT - Positioning and Displaying a Custom Widget

12,493

Couple of things I noticed in your code:

  1. you don't really need to define store x, y, width and height for your custom widget. Just call setGeometry with coordinates passed into the constructor. Widget already providers getGeometry, getHeight, getWidth, etc. methods which you can use to manipulate and paint your component.

  2. when you call drawEllipse in the child widget drawLink method, you're passing x and y coordinates into the function as rectangle beginning. From my understanding you should put there 0, 0 as those coordinates should be widget relative not the window relative.

I've made some changes to your code, see if it works for you

import sys, random
from PyQt4 import QtGui, QtCore

# Robot Widget
class RobotLink(QtGui.QWidget):
    def __init__(self, parent, x, y, width, height, fill):
        super(RobotLink, self).__init__(parent)
        self._fill     = fill
        self._rotation = 0
        self.setGeometry(x, y, width, height)

    def paintEvent(self, e):
        painter = QtGui.QPainter()
        painter.begin(self)
        self.drawLink(painter)
        painter.end()

    def drawLink(self, painter):
        painter.setPen(QtGui.QColor(0, 0, 0))
        painter.setBrush(self._fill)
        painter.drawEllipse(0, 0, self.width(), self.height())

# Window
class Window(QtGui.QWidget):
    # Default Constructor, sets up the window GUI
    def __init__(self):
        super(Window, self).__init__()
        self.initUI()

    def initUI(self):
        self._link1 = RobotLink(self, 10, 10, 100, 50, QtCore.Qt.DiagCrossPattern)
        self._link2 = RobotLink(self, 100, 100, 50, 100, QtCore.Qt.Dense5Pattern)
        self._link3 = RobotLink(self, 150, 150, 50, 50, QtCore.Qt.Dense2Pattern)

        self.setGeometry(300, 300, 800, 600)
        self.setWindowTitle("CSCE 452 - PaintBot")

    def paintEvent(self, e):
        super(Window, self).paintEvent(e)
        painter = QtGui.QPainter()
        painter.begin(self)
        self.drawBoundingBoxes(painter)
        painter.end()

    # Draws the boxes that define the robots workspace and
    # the control panel
    def drawBoundingBoxes(self, painter):
        color = QtGui.QColor(0, 0, 0)
        color.setNamedColor("#cccccc")
        painter.setPen(color)

        # Draw the robot workspace
        painter.setBrush(QtGui.QColor(255, 255, 255))
        painter.drawRect(10, 10, 500, 578)

        # Draw the control panel workspace
        painter.setBrush(QtGui.QColor(150, 150, 150))
        painter.drawRect(520, 10, 270, 578)

        # Draws the slider 'base'
        painter.setPen(QtGui.QColor(0, 0, 0))
        painter.drawLine(100, 570, 400, 570)

    def changeValue(self, value):
        self.wid.emit(QtCore.SIGNAL("updateRobot(int)"), value)
        self.wid.repaint()

# Setup the Window, and the Robot
app = QtGui.QApplication(sys.argv)
win = Window()
win.show()
app.exec_()

hope this helps, regards

Share:
12,493
Julio
Author by

Julio

Updated on June 04, 2022

Comments

  • Julio
    Julio almost 2 years

    I am attempting to use PyQT to position and display a custom widget. Thus far, I have a widget, and my window. I have been successful in displaying the widget through a layout, however, I am interested in using .move(x,y,) to position my widget before show()'ing it. Thus far my code is as follows:

    import sys, random
    from PyQt4 import QtGui, QtCore
    
    # Robot Widget
    class RobotLink(QtGui.QWidget):
        def __init__(self, parent, x, y, width, height, fill):
            super(RobotLink, self).__init__(parent)
            self._x        = x
            self._y        = y
            self._width    = width
            self._height   = height
            self._fill     = fill
            self._rotation = 0
    
        def paintEvent(self, e):
            painter = QtGui.QPainter()
            painter.begin(self)
            self.drawLink(painter)
            painter.end()
    
        def drawLink(self, painter):
            painter.setPen(QtGui.QColor(0, 0, 0))
            painter.setBrush(self._fill)
            painter.drawEllipse(self._x, self._y, self._width, self._height)
    
    # Window
    class Window(QtGui.QWidget):
        # Default Constructor, sets up the window GUI
        def __init__(self):
            super(Window, self).__init__()
            self.initUI()
    
        def initUI(self):
            self._link1 = RobotLink(self, 225, 400, 30, 150, QtCore.Qt.DiagCrossPattern)
            self._link2 = RobotLink(self, 0, 320, 30, 100, QtCore.Qt.Dense5Pattern)
            self._link3 = RobotLink(self, 225, 260, 30, 75, QtCore.Qt.Dense2Pattern)
    
            self._link1.move(0, 0)
            self._link1.show()
    
            self.setGeometry(300, 300, 800, 600)
            self.setWindowTitle("CSCE 452 - PaintBot")
    
    
        def paintEvent(self, e):
            super(Window, self).paintEvent(e)
            painter = QtGui.QPainter()
            painter.begin(self)
            self.drawBoundingBoxes(painter)
            painter.end()
    
        # Draws the boxes that define the robots workspace and
        # the control panel
        def drawBoundingBoxes(self, painter):
            color = QtGui.QColor(0, 0, 0)
            color.setNamedColor("#cccccc")
            painter.setPen(color)
    
            # Draw the robot workspace
            painter.setBrush(QtGui.QColor(255, 255, 255))
            painter.drawRect(10, 10, 500, 578)
    
            # Draw the control panel workspace
            painter.setBrush(QtGui.QColor(150, 150, 150))
            painter.drawRect(520, 10, 270, 578)
    
            # Draws the slider 'base'
            painter.setPen(QtGui.QColor(0, 0, 0))
            painter.drawLine(100, 570, 400, 570)
    
        def changeValue(self, value):
            self.wid.emit(QtCore.SIGNAL("updateRobot(int)"), value)
            self.wid.repaint()
    
    # Setup the Window, and the Robot
    app = QtGui.QApplication(sys.argv)
    win = Window()
    win.show()
    app.exec_()
    

    Any idea how to attach my widget, without a layout, position it and have it show inside of my window?