Hopefully I am following the guidelines correctly here with my first question. I am trying to create a GUI with the MVC structure. I am having difficulty with understanding why my signals are not always being picked up by the controller. I know that there is just something simple that I'm missing. I'm attaching code from a simple calculator which I used as a guide. I removed most of the features to simplify this as much as possible. It is now only 3 of the original buttons and my own button. For debugging, I just have the value on the button printed out when you press it.
import sys
# Import QApplication and the required widgets from PyQt5.QtWidgets
from PySide2.QtWidgets import QApplication
from PySide2.QtWidgets import QMainWindow
from PySide2.QtWidgets import QWidget
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QGridLayout
from PySide2.QtWidgets import QLineEdit
from PySide2.QtWidgets import QPushButton
from PySide2.QtWidgets import QVBoxLayout
from functools import partial
ERROR_MSG = 'ERROR'
# Create a subclass of QMainWindow to setup the calculator's GUI
class PyCalcUi(QMainWindow):
"""PyCalc's View (GUI)."""
def __init__(self):
"""View initializer."""
super().__init__()
# Set some main window's properties
self.setWindowTitle('PyCalc')
self.setFixedSize(235, 235)
# Set the central widget and the general layout
self.generalLayout = QVBoxLayout()
self._centralWidget = QWidget(self)
self.setCentralWidget(self._centralWidget)
self._centralWidget.setLayout(self.generalLayout)
# Create the display and the buttons
self._createDisplay()
self._createButtons()
def _createDisplay(self):
"""Create the display."""
# Create the display widget
self.display = QLineEdit()
# Set some display's properties
self.display.setFixedHeight(35)
self.display.setAlignment(Qt.AlignRight)
self.display.setReadOnly(True)
# Add the display to the general layout
self.generalLayout.addWidget(self.display)
def _createButtons(self):
"""Create the buttons."""
self.buttons = {}
buttonsLayout = QGridLayout()
# Button text | position on the QGridLayout
buttons = {'7': (0, 0),
'8': (0, 1),
'9': (0, 2),
}
# Create the buttons and add them to the grid layout
for btnText, pos in buttons.items():
self.buttons[btnText] = QPushButton(btnText)
self.buttons[btnText].setFixedSize(40, 40)
buttonsLayout.addWidget(self.buttons[btnText], pos[0], pos[1])
self.mybutton = QPushButton("5")
buttonsLayout.addWidget(self.mybutton,1,0)
# Add buttonsLayout to the general layout
self.generalLayout.addLayout(buttonsLayout)
# Create a Controller class to connect the GUI and the model
class PyCalcCtrl:
"""PyCalc Controller class."""
def __init__(self, model, view):
"""Controller initializer."""
self._evaluate = model
self._view = view
# Connect signals and slots
self._connectSignals()
def _printthis(self):
print("Hi")
def _printthat(self, buttonvalue):
print(buttonvalue)
def _connectSignals(self):
"""Connect signals and slots."""
self._view.mybutton.clicked.connect(self._printthis)
for btnText, btn in self._view.buttons.items():
btn.clicked.connect(partial(self._printthat, btnText))
# Create a Model to handle the calculator's operation
def evaluateExpression(expression):
"""Evaluate an expression."""
try:
result = str(eval(expression, {}, {}))
except Exception:
result = ERROR_MSG
return result
# Client code
def main():
"""Main function."""
# Create an instance of QApplication if it doesn't exist
pycalc = QApplication.instance()
if pycalc is None:
pycalc = QApplication(sys.argv)
# Show the calculator's GUI
view = PyCalcUi()
view.show()
# Create instances of the model and the controller
model = evaluateExpression
PyCalcCtrl(model=model, view=view)
# Execute the calculator's main loop
sys.exit(pycalc.exec_())
if __name__ == '__main__':
main()
This set of code works, BUT if I comment out the
for btnText, btn in self._view.buttons.items():
btn.clicked.connect(partial(self._printthat, btnText))
The self._view.mybutton.clicked.connect(self._printthis) will no longer work.
What is the btn.clicked.connect(partial(self._printthat, btnText)) line doing which is allowing any other signal I put in def _connectSignals(self): to work. What aspect of that line is achieving something that the mybutton signal isn't doing?
The problem is caused because the PyCalcCtrl object is not assigned to a variable so it will be destroyed and therefore the "_printthis" method will not be accessible. On the other hand, when functools.partial is used then the object of the PyCalcCtrl class is assigned to the scope of that function, that's why it works.
The solution is to assign the PyCalcCtrl object to a variable:
ctrl = PyCalcCtrl(model=model, view=view)
Related
I'm running a simple code to creat 4 checkboxes in a widget
I have a simple function to change the checkbox text when clicked based on wheater it's checked or not
I'm trying to connect the "clicked" signal to slot "on_checkBox_ss" using Lambda method to pass an extar parameter to identify the clicked checkbox
but it's not working well, it pass False/True instead of the checkbox index
here is the code
from PyQt6 import QtWidgets
from PyQt6.QtWidgets import QWidget, QCheckBox, QApplication, QVBoxLayout
class mainwidget():
def __init__(self) -> None:
super().__init__()
self.widget = QWidget()
vlayout = QVBoxLayout(self.widget)
self.CHK_BoxGRP = [checkBoxClass(self.widget,f"ChkBox_{x}") for x in range(0,4)]
[vlayout.addWidget(self.CHK_BoxGRP[i].chkbox) for i in range(0,4)]
# Build the connection
[self.CHK_BoxGRP[y].chkbox.clicked.connect(lambda y:self.on_checkBox_ss(y)) for
y in range (0,4)]
#function to process the clicked checkbox
def on_checkBox_ss(self,boxnum):
if self.CHK_BoxGRP[boxnum].chkbox.isChecked():
self.CHK_BoxGRP[boxnum].chkbox.setText("Clicked")
else:
self.CHK_BoxGRP[boxnum].chkbox.setText("Not Clicked")
""" Below is check box class """
class checkBoxClass:
def __init__(self,PARENT,CHKLABEL) -> None:
#super().__init__()
self.parent = PARENT
self.chkLabel = CHKLABEL
#self.operat_on = OPERAT_ON
self.chkbox = QtWidgets.QCheckBox(self.parent)
self.chkbox.setStyleSheet("border-color: rgb(85, 85, 255);")
self.chkbox.setObjectName(self.chkLabel)
self.chkbox.setChecked(True)
self.chkbox.setText(f"GROUP {self.chkLabel[-1]}")
""" start of main code"""
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
mainwindow = mainwidget()
mainwindow.widget.show()
sys.exit(app.exec())
QPushButton.clicked.connect() method automatically passes the state of the button (bool) as default first argument, so if there is only one argument -which is 'y' in comprehension in this case- is overwritten with the state of the button.
You can see that if you just print(boxnum) in 'on_checkBox_ss', it prints out True or False which is the state of clicked button, and by coincidence list[True] will return #1 index and list[False] will return #0 (as it should be because boolean expressions are just 0 or 1 at the end of the day)
I said that this was a coincidence because your code actually works (just not the way as intended) and doesn't give an error which make it seem like the problem has something to do with signals and loops in the framework.
So the solution is to overwrite the state argument with anything (which will be 'x' -or anything for that matter) and pass 'y' explicitly.
[self.CHK_BoxGRP[y].chkbox.clicked.connect(lambda x="", y=y: self.on_checkBox_ss(y)) for y in range(4)]
So it will be:
from PyQt6 import QtWidgets
from PyQt6.QtWidgets import QWidget, QCheckBox, QApplication, QVBoxLayout
class mainwidget():
def __init__(self) -> None:
super().__init__()
self.widget = QWidget()
vlayout = QVBoxLayout(self.widget)
self.CHK_BoxGRP = [checkBoxClass(self.widget,f"ChkBox_{x}") for x in range(0,4)]
[vlayout.addWidget(self.CHK_BoxGRP[i].chkbox) for i in range(0,4)]
# Build the connection
#[self.CHK_BoxGRP[y].chkbox.clicked.connect(lambda y:self.on_checkBox_ss(y)) for
#y in range (0,4)]
[self.CHK_BoxGRP[y].chkbox.clicked.connect(lambda x="", y=y:self.on_checkBox_ss(y)) for y in range(4)]
#function to process the clicked checkbox
def on_checkBox_ss(self,boxnum):
print(boxnum) # now prints out actual y value instead of True or False
if self.CHK_BoxGRP[boxnum].chkbox.isChecked():
self.CHK_BoxGRP[boxnum].chkbox.setText("Clicked")
else:
self.CHK_BoxGRP[boxnum].chkbox.setText("Not Clicked")
""" Below is check box class """
class checkBoxClass:
def __init__(self,PARENT,CHKLABEL) -> None:
#super().__init__()
self.parent = PARENT
self.chkLabel = CHKLABEL
#self.operat_on = OPERAT_ON
self.chkbox = QtWidgets.QCheckBox(self.parent)
self.chkbox.setStyleSheet("border-color: rgb(85, 85, 255);")
self.chkbox.setObjectName(self.chkLabel)
self.chkbox.setChecked(True)
self.chkbox.setText(f"GROUP {self.chkLabel[-1]}")
""" start of main code"""
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
mainwindow = mainwidget()
mainwindow.widget.show()
sys.exit(app.exec())
If I click Back from the second window, the program will just exit. How do I go back to mainwindow in this case? I assume I will need some more code in that clickMethodBack function.
import os
import PyQt5
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QWidget, QLabel, QPushButton
import time
from PyQt5.QtCore import QSize
class GUI_Window():
def __init__(self):
self.main_window()
return
def main_window(self):
app = PyQt5.QtWidgets.QApplication(sys.argv)
self.MainWindow = MainWindow_()
self.MainWindow.show()
app.exec_()
return
class MainWindow_(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.TestAButton = QPushButton("TestA", self)
self.TestAButton.clicked.connect(self.TestA_clickMethod)
self.TestAButton.move(20, 0)
self.CloseButton = QPushButton("Close", self)
self.CloseButton.clicked.connect(self.Close_clickMethod)
self.CloseButton.move(20, 40)
self.TestingA = TestA_MainWindow()
def TestA_clickMethod(self):
self.TestAButton.setEnabled(False)
time.sleep(0.2)
self.TestingA.show()
self.hide()
try:
if self.TestingA.back == True:
self.show()
except:
None
def Close_clickMethod(self):
self.Test_Choice = 'Exit'
self.close()
class TestA_MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setMinimumSize(QSize(980,700))
self.setWindowTitle("TestA")
self.Back_Button = False
self.closeButton = QPushButton("Close", self)
self.closeButton.clicked.connect(self.clickMethodClose)
self.returnButton = QPushButton("Back", self)
self.returnButton.clicked.connect(self.clickMethodBack)
self.returnButton.move(0,30)
def clickMethodClose(self):
self.Back_Button = False
self.close()
def clickMethodBack(self):
self.returnButton.setEnabled(False)
time.sleep(0.5)
self.back = True
self.close()
# Run if Script
if __name__ == "__main__":
main = GUI_Window() # Initialize GUI
Your code has two very important issues.
you're using a blocking function, time.sleep; Qt, as almost any UI toolkit, is event driven, which means that it has to be able to constantly receive and handle events (coming from the system or after user interaction): when something blocks the event queue, it completely freezes the whole program until that block releases control;
you're checking for the variable too soon: even assuming the sleep would work, you cannot know if the window is closed after that sleep timer has ended;
The solution is to use signals and slots. Since you need to know when the second window has been closed using the "back" button, create a custom signal for the second window that will be emitted whenever the function that is called by the button is closed.
from PyQt5 import QtCore, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
central = QtWidgets.QWidget()
layout = QtWidgets.QHBoxLayout(central)
self.testButton = QtWidgets.QPushButton('Test A')
self.closeButton = QtWidgets.QPushButton('Close')
layout.addWidget(self.testButton)
layout.addWidget(self.closeButton)
self.setCentralWidget(central)
self.testButton.clicked.connect(self.launchWindow)
self.closeButton.clicked.connect(self.close)
def launchWindow(self):
self.test = TestA_MainWindow()
self.test.backSignal.connect(self.show)
self.hide()
self.test.show()
class TestA_MainWindow(QtWidgets.QWidget):
backSignal = QtCore.pyqtSignal()
def __init__(self):
super().__init__()
layout = QtWidgets.QHBoxLayout(self)
self.closeButton = QtWidgets.QPushButton('Close')
self.backButton = QtWidgets.QPushButton('Back')
layout.addWidget(self.closeButton)
layout.addWidget(self.backButton)
self.closeButton.clicked.connect(self.close)
self.backButton.clicked.connect(self.goBack)
def goBack(self):
self.close()
self.backSignal.emit()
def GUI_Window():
import sys
app = QtWidgets.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())
if __name__ == '__main__':
GUI_Window()
Notes:
I removed the GUI_Window class and made a function, as using a class for that is not really useful;
you should always prefer layout managers instead of setting manual geometries;
widgets should not be added to a QMainWindow as direct children, and a central widget should always be used (see the creation and use of central in the example); read more about it in the documentation;
only classes and constants should be capitalized, while variables, attributes and functions should always have names starting with a lowercase letter;
Hopefully I am following the guidelines correctly here with my first question. I am trying to create a GUI with the MVC structure. I am having difficulty with understanding why my signals are not always being picked up by the controller. I know that there is just something simple that I'm missing. I'm attaching code from a simple calculator which I used as a guide. I removed most of the features to simplify this as much as possible. It is now only 3 of the original buttons and my own button. For debugging, I just have the value on the button printed out when you press it.
import sys
# Import QApplication and the required widgets from PyQt5.QtWidgets
from PySide2.QtWidgets import QApplication
from PySide2.QtWidgets import QMainWindow
from PySide2.QtWidgets import QWidget
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QGridLayout
from PySide2.QtWidgets import QLineEdit
from PySide2.QtWidgets import QPushButton
from PySide2.QtWidgets import QVBoxLayout
from functools import partial
ERROR_MSG = 'ERROR'
# Create a subclass of QMainWindow to setup the calculator's GUI
class PyCalcUi(QMainWindow):
"""PyCalc's View (GUI)."""
def __init__(self):
"""View initializer."""
super().__init__()
# Set some main window's properties
self.setWindowTitle('PyCalc')
self.setFixedSize(235, 235)
# Set the central widget and the general layout
self.generalLayout = QVBoxLayout()
self._centralWidget = QWidget(self)
self.setCentralWidget(self._centralWidget)
self._centralWidget.setLayout(self.generalLayout)
# Create the display and the buttons
self._createDisplay()
self._createButtons()
def _createDisplay(self):
"""Create the display."""
# Create the display widget
self.display = QLineEdit()
# Set some display's properties
self.display.setFixedHeight(35)
self.display.setAlignment(Qt.AlignRight)
self.display.setReadOnly(True)
# Add the display to the general layout
self.generalLayout.addWidget(self.display)
def _createButtons(self):
"""Create the buttons."""
self.buttons = {}
buttonsLayout = QGridLayout()
# Button text | position on the QGridLayout
buttons = {'7': (0, 0),
'8': (0, 1),
'9': (0, 2),
}
# Create the buttons and add them to the grid layout
for btnText, pos in buttons.items():
self.buttons[btnText] = QPushButton(btnText)
self.buttons[btnText].setFixedSize(40, 40)
buttonsLayout.addWidget(self.buttons[btnText], pos[0], pos[1])
self.mybutton = QPushButton("5")
buttonsLayout.addWidget(self.mybutton,1,0)
# Add buttonsLayout to the general layout
self.generalLayout.addLayout(buttonsLayout)
# Create a Controller class to connect the GUI and the model
class PyCalcCtrl:
"""PyCalc Controller class."""
def __init__(self, model, view):
"""Controller initializer."""
self._evaluate = model
self._view = view
# Connect signals and slots
self._connectSignals()
def _printthis(self):
print("Hi")
def _printthat(self, buttonvalue):
print(buttonvalue)
def _connectSignals(self):
"""Connect signals and slots."""
self._view.mybutton.clicked.connect(self._printthis)
for btnText, btn in self._view.buttons.items():
btn.clicked.connect(partial(self._printthat, btnText))
# Create a Model to handle the calculator's operation
def evaluateExpression(expression):
"""Evaluate an expression."""
try:
result = str(eval(expression, {}, {}))
except Exception:
result = ERROR_MSG
return result
# Client code
def main():
"""Main function."""
# Create an instance of QApplication if it doesn't exist
pycalc = QApplication.instance()
if pycalc is None:
pycalc = QApplication(sys.argv)
# Show the calculator's GUI
view = PyCalcUi()
view.show()
# Create instances of the model and the controller
model = evaluateExpression
PyCalcCtrl(model=model, view=view)
# Execute the calculator's main loop
sys.exit(pycalc.exec_())
if __name__ == '__main__':
main()
This set of code works, BUT if I comment out the
for btnText, btn in self._view.buttons.items():
btn.clicked.connect(partial(self._printthat, btnText))
The self._view.mybutton.clicked.connect(self._printthis) will no longer work.
What is the btn.clicked.connect(partial(self._printthat, btnText)) line doing which is allowing any other signal I put in def _connectSignals(self): to work. What aspect of that line is achieving something that the mybutton signal isn't doing?
The problem is caused because the PyCalcCtrl object is not assigned to a variable so it will be destroyed and therefore the "_printthis" method will not be accessible. On the other hand, when functools.partial is used then the object of the PyCalcCtrl class is assigned to the scope of that function, that's why it works.
The solution is to assign the PyCalcCtrl object to a variable:
ctrl = PyCalcCtrl(model=model, view=view)
I'm trying to create an application with PyQT5 using the MVC architecture and I'm having trouble understanding how to send some of the information from the model to the view. In the sample application below, I have a countdown timer running in the model and I'd like the progress bar in the View to track it's progress. But I'm unsure how to send information to the view from the model when the method in the model is being executed. In my case, the progress_bar gets updated only after the execution of the model.counter method has completed executed. What would be a graceful way of handling this ? I need the progress_bar to update as model.i gets updated.
import sys
import time
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget
from PyQt5.QtWidgets import QGridLayout, QLineEdit, QPushButton, QVBoxLayout, QProgressBar
from PyQt5.QtCore import Qt
class ExampleGUI(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('Sample Application')
# Set some main window's properties
self.setFixedSize(235, 235)
# Set the central widget and the general layout
self.generalLayout = QVBoxLayout()
self._centralWidget = QWidget(self)
self.setCentralWidget(self._centralWidget)
self._centralWidget.setLayout(self.generalLayout)
# Create the display and the buttons
self._createDisplay()
self._createButtons()
def _createDisplay(self):
"""Create the display."""
# Create the display widget
self.display = QLineEdit()
self.progress_bar = QProgressBar()
# Set some display's properties
self.display.setFixedHeight(35)
self.display.setAlignment(Qt.AlignRight)
self.display.setReadOnly(True)
# Add the display to the general layout
self.generalLayout.addWidget(self.display)
self.generalLayout.addWidget(self.progress_bar)
def _createButtons(self):
"""Create the buttons."""
buttonsLayout = QGridLayout()
self.button1 = QPushButton("Start")
self.button1.setFixedSize(80, 40)
self.button2 = QPushButton("Clear")
self.button2.setFixedSize(80, 40)
buttonsLayout.addWidget(self.button1)
buttonsLayout.addWidget(self.button2)
self.generalLayout.addLayout(buttonsLayout)
def setDisplayText(self, text):
"""Set display's text."""
self.display.setText(text)
self.display.setFocus()
def clearDisplay(self):
"""Clear the display."""
self.setDisplayText("")
class Model:
def __init__(self):
self.counter = ''
self.i = ''
def countdown(self, counter):
self.i = 0
self.counter = counter
while self.i < self.counter:
self.i+=1
time.sleep(1)
return True
class Controller:
def __init__(self, view, model):
self._view = view
self._model = model
self._connect_settings_signals()
def _set_message(self):
self._view.progress_bar.setMaximum(10)
reply = self._model.countdown(10)
self._view.progress_bar.setValue(self._model.i)
if reply:
self._view.setDisplayText("Countdown complete!")
def _clear_message(self):
self._view.clearDisplay()
def _connect_settings_signals(self):
self._view.button1.clicked.connect(self._set_message)
self._view.button2.clicked.connect(self._clear_message)
def main():
"""Main function."""
# Create an instance of `QApplication`
pycalc = QApplication(sys.argv)
# Show the calculator's GUI
view = ExampleGUI()
view.show()
model = Model()
# Create instances of the model and the controller
ctrl = Controller(view=view, model=model)
# Execute calculator's main loop
sys.exit(pycalc.exec_())
if __name__ == "__main__":
main()
That sleep(1) is blocking operation and event loop returns to '_set_message' only after 'countdown' is finished.
I would move update of model and loop out of model, back to controller. (As its kind of controlling, telling model update its value, wait a bit...)
I would update to something similar as:
def _set_message(self):
self._view.progress_bar.setMaximum(10)
self.i = 0
while self.i < 10:
self.i+=1
self._model.i += 1
self._view.progress_bar.setValue(self._model.i)
time.sleep(1)
self._view.setDisplayText("Countdown complete!")
If you would insist on looping and sleeping in model (I don't think thats a good idea), you would have to dive into threading, create separate thread for that operation, and keep main event loop unblocked for redrawing of progress bar. (imho)
I am trying to develop a GUI to show my robot and obstacles around it. I created a class GUI and it has a member function showObstacle to show obstacle. Since I want to keep all the obstacles in place, I create new obstacle object in a vector to store all the objects.
I called this function in class's init function to test and it was successful.
But when I call this function in different class, it doesn't show the obstacles on the GUI window. In class TCP_Connection (where I get information about the robot), I created myGui class and I called showObstacle function.
After debugging, it turns out it creates the Obstacle Objects whenever it is called, but it doesn't display it on the window
#this is file 1, GUI Class
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget
from PyQt5.QtCore import Qt
from pynput import keyboard
class App(QWidget):
def __init__(self, OtherWindow):
super().__init__()
self.setGeometry(100,100,440,800)
self.setWindowTitle("New GUI Interface Window")
self.currentState = 0
self.obstCounter = 0
self.d = []
#testing showObstacle
self.showObstacle(205, 305) #this works
self.showObstacle(210,315) #this also works
self.show()
def showObstacle(self, Obs_x, Obs_y):
self.obstImage = QtGui.QImage('obsta_edited.png')
self.pixmap_obst = QtGui.QPixmap(self.obstImage)
self.d.append("O{0}".format(self.obstCounter))
self.d[self.obstCounter] = QtWidgets.QLabel(self)
self.d[self.obstCounter].setPixmap(self.pixmap_obst)
self.d[self.obstCounter].move(Obs_x, Obs_y)
self.d[self.obstCounter].adjustSize()
self.obstCounter += 1
print(self.d)
print("Obstacle Run")
this is the calling class
from myGUI import App
from PyQt5.QtWidgets import QWidget,QLabel,QLineEdit, QHBoxLayout,QVBoxLayout,QMainWindow,QPushButton, QFrame, QDesktopWidget, QApplication
from PyQt5.Qt import QStackedLayout
import sys, random
class TCP_Communication:
def __init__(self):
super().__init__()
self.openWindow()
def openWindow(self):
self.window = QMainWindow()
self.myGui = App(self.window)
self.myGui.showObstacle(215, 320)
self.stacked_layout = QStackedLayout()
self.stacked_layout.addWidget(self.myGui)
def tcp_showObstacle(self,x,y):
self.myGui.showObstacle(x,y)
if __name__ == '__main__':
app = QApplication([])
tcp_com = TCP_Communication()
sys.exit(app.exec_())
Edited : attached the result ; Suppose to show 4 obstacles but only shows 2
Edited2 : Code is executable now
The problem is that the QLabels are not showing, the main widget when displayed at the beginning makes your children show up, but after that it does not make them visible, as it is in your case, so your task is to call their method show() directly:
def showObstacle(self, Obs_x, Obs_y):
pixmap_obst = QtGui.QPixmap('obsta_edited.png')
self.d.append("O{0}".format(self.obstCounter))
label = QtWidgets.QLabel(self)
label.setPixmap(pixmap_obst)
label.move(Obs_x, Obs_y)
label.adjustSize()
label.show() # <---show QLabel
self.d[self.obstCounter] = label
self.obstCounter += 1
print(self.d)
print("Obstacle Run")