Pass an argument with QtCore.SIGNAL - python

Code:
class Text(QtGui.QLabel):
def __init__(self,parent):
QtGui.QLabel.__init__(self,parent)
def mouseReleaseEvent(self,evt):
pos = evt.pos()
if pos.x() < 0 or pos.y() < 0 or pos.x() > self.width() or pos.y() > self.height():
return
self.parent().update()
self.emit(QtCore.SIGNAL('clicked()'))
def updateText(self, txt):
self.setText(txt)
class Window(QtGui.QMainWindow):
def createNews(self):
self.a1 = Text(self)
self.a1.updateText("Test")
self.a1.setFixedWidth(200)
self.a1.move(23, 173)
self.a1.show()
self.connect(self.a1, QtCore.SIGNAL("clicked()"), self.OpenURL)
def OpenURL(self, URL):
QtGui.QDesktopServices.openUrl(QtCore.QUrl(str(URL)))
I'm trying to make a "clickable" label, so that if I click it, it will open a URL passed in the argument via self.connect(self.a1, QtCore.SIGNAL("clicked()"), self.OpenURL).
The question is, if it's possible to pass an argument (url) to self.OpenURL() so it could open the URL?

Firstly, you should get rid of the old-style signal syntax, and define a custom clicked signal, like this:
class Text(QtGui.QLabel):
clicked = QtCore.pyqtSignal()
def mouseReleaseEvent(self, evt):
...
self.clicked.emit()
Then use a lambda to send the argument with the signal:
self.a1.clicked.connect(lambda: self.OpenURL(url))
More information about new-style signal/slot syntax can be found here.

Related

Update Text Entity in Ursina, Python

I have this code:
BUTTON_INDENT = -1
class TIME(Text):
def __init__(self):
super().__init__(
text=time.strftime("%H:%M"),
position=(0,0,BUTTON_INDENT),
)
How do I make it so the text inside changes?
I have tried this before too:
BUTTON_INDENT = -1
class TIME(Text):
def __init__(self):
super().__init__(
text=time.strftime("%H:%M"),
position=(0,0,BUTTON_INDENT)
)
def update(self):
self.text = time.strftime("%H:%M")
That doesn't seem to make the text change either.
Anyhow, the update function doesn't work in Text class, here is the full updated code :
from ursina import *
app = Ursina()
BUTTON_INDENT = -1
class TIME(Text):
def __init__(self):
super().__init__()
self.text=time.strftime("%H:%M:%S")
self.position=(0,0,BUTTON_INDENT)
t = TIME()
def update():
t.text = time.strftime("%H:%M:%S")
app.run()

How to implement buttons in a delegate PyQt

I am making a program for translating text (see screenshot)
I have three classes
class for displaying a window that edits item :
class StyleDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
super(StyleDelegate, self).__init__()
def createEditor(self, widget, style, index):
self.mainWidget = QWidget(widget)
self.line = QLineEdit() # line for input text
self.delButton= QPushButton('❌') # button for delete current item
self.trnButton = QPushButton('➕') # button for make translation text in another QListView
self.qhbLayout = QHBoxLayout()
self.qhbLayout.addWidget(self.line)
self.qhbLayout.addWidget(self.delButton)
self.qhbLayout.addWidget(self.trnButton)
self.mainWidget.setLayout(self.qhbLayout)
return self.mainWidget
# there is still a lot of code in this place
class for storing, adding, deleting and editing data:
class TranslateListModel(QAbstractListModel):
def __init__(self, parent=None):
super(TranslateListModel, self).__init__()
self.words = ['1', '2', '3', '4']
def removeItem(self, index):
self.beginRemoveRows(index, index.row(), index.row())
del self.words[index.row()]
self.endRemoveRows()
return True
# there is still a lot of code in this place
main class of the program:
class QTranslate(QtWidgets.QDialog, log.Ui_Dialog):
def __init__(self):
super().__init__()
self.originalModel = TranslateListModel()
self.translateModel = TranslateListModel()
self.styleDelegate = StyleDelegate()
self.originalLV.setModel(self.originalModel)
#QListView from Ui_Dialog
self.translateLV.setModel(self.translateModel)
#QListView from Ui_Dialog
self.originalLV.setItemDelegate(self.styleDelegate)
self.translateLV.setItemDelegate(self.styleDelegate)
# there is still a lot of code in this place
How to implement buttons to delete the current item and change the translation in another QListView using QStyledItemDelegate? I cannot access these buttons outside the StyleDelegate class to associate them with the methods of the TranslateListModel class.
A possible solution is to create signals for the delegate and connect them to the functions that will delete or add items, then emit those signals when the buttons are clicked:
class StyleDelegate(QStyledItemDelegate):
deleteRequested = QtCore.pyqtSignal(int)
translateRequested = QtCore.pyqtSignal(int)
def __init__(self, parent=None):
super(StyleDelegate, self).__init__()
def createEditor(self, widget, style, index):
# note: I removed the "self" references as they're unnecessary
mainWidget = QWidget(widget)
line = QLineEdit()
delButton= QPushButton('❌')
trnButton = QPushButton('➕')
qhbLayout = QHBoxLayout()
qhbLayout.addWidget(line)
qhbLayout.addWidget(delButton)
qhbLayout.addWidget(trnButton)
mainWidget.setLayout(qhbLayout)
delButton.clicked.connect(
lambda _, row=index.row(): self.deleteRequested.emit(row))
trnButton.clicked.connect(
lambda _, row=index.row(): self.translateRequested.emit(row))
return mainWidget
class QTranslate(QtWidgets.QDialog, log.Ui_Dialog):
def __init__(self):
# ...
self.originalLV.setItemDelegate(self.styleDelegate)
self.styleDelegate.deleteRequested.connect(self.deleteRow)
self.styleDelegate.translateRequested.connect(self.translateRow)
def deleteRow(self, row):
# ...
def translateRow(self, row):
# ...
Note that you should always use an unique delegate instance for each view, as explained in the documentation:
Warning: You should not share the same instance of a delegate between views. Doing so can cause incorrect or unintuitive editing behavior since each view connected to a given delegate may receive the closeEditor() signal, and attempt to access, modify or close an editor that has already been closed.

Changing a button connection to another function

I have an application that works kind of like a slide show: I have a button that changes the background picture when clicked. I also have a second button that helps go back to the previous picture. The problem is, that the first button gets another function at the end of the show, but after that I am not able to change the function back to the previous one when I click the back button.
My code looks somewhat like this, I hope this makes my problem clear:
class SecondWindow(TemplateBaseClass):
def back(self):
self.first.n = self.first.n-2
self.hide()
self.first.show()
self.first.nextPicture()
def __init__(self):
TemplateBaseClass.__init__(self)
self.ui = WindowTemplate()
self.ui.setupUi(self)
self.first = MainWindow(self)
self.first.showFullScreen()
self.ui.pushButton.clicked.connect(lambda x:self.back())
class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def showSecond(self):
#QTimer.singleShot(25, MainWindow)
self.second.showFullScreen()
self.hide()
def back(self):
if self.n >= 2:
self.n = self.n-2
self.notBack = False
self.nextPicture()
# I tried in several places like here, but it does not work
self.ui.end_button.clicked.connect(lambda x:self.nextPicture())
def nextPicture(self):
print(self.n)
if self.n == 0:
self.ui.bg_widget.setStyleSheet("background-image: url(:/ux/img0.png);\nbackground-repeat:no-repeat;")
elif self.n ==1 :
self.ui.bg_widget.setStyleSheet("background-image: url(:/ux/img1.png);\nbackground-repeat:no-repeat;")
elif self.n == 2:
self.ui.bg_widget.setStyleSheet("background-image: url(:/ux/img2.png);\nbackground-repeat:no-repeat;")
if self.notBack:
self.ui.end_button.clicked.connect(lambda x:self.showSecond())
else:
self.ui.end_button.clicked.connect(lambda x:self.nextPicture())
self.n +=1
self.notBack = True
def __init__(self, second):
QtGui.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.second = second
self.setWindowTitle('pyqtgraph example: Qt Designer')
self.ui=uic.loadUi(uiFile, self)
self.setupUi(self)
self.setWindowFlags(QtCore.Qt.CustomizeWindowHint)
self.showFullScreen()
self.n = 1
self.notBack = True
self.ui.end_button.clicked.connect(lambda x:self.nextPicture())
self.ui.backButton.clicked.connect(lambda x:self.back())
A simple disconnect() solves the issue:
def back(self):
if self.n >= 2:
self.n = self.n-2
self.notBack = False
self.nextPicture()
self.ui.end_button.disconnect()
self.ui.end_button.clicked.connect(lambda x:self.nextPicture())

collidesWithItem() function not detecting collision (PyQt)

I'm writing an application that allows the user to add items to a scene. I dont want any new items being drawn over items that have already been drawn and to do that I decided to use the collidesWithItem() function to detect collision. With my code i still can draw over added items even though there is obviously collision and I debugged the program and the collidesWithItem() function keeps returning "False".
The items are added by clicking on the toolbar of the Form.
Down below is my code:
class graphicsScene(QtGui.QGraphicsScene, QtGui.QWidget):
def __init__(self, parent=None):
super(graphicsScene, self).__init__(parent)
self.i = 0
self.setSceneRect(-180, -90, 360, 180)
global overlapped
overlapped = 0
def mousePressEvent(self, event):
global host_cs
global overlapped
if host_cs == 1:
if len(hostItem_list) == 0:
self.host_item = host_Object()
hostItem_list.append(self.host_item.host_pixItem)
else:
self.host_item = host_Object()
for host in hostItem_list:
if self.host_item.host_pixItem.collidesWithItem(host):
print 'collision'
overlapped = 1
break
elif self.host_item.host_pixItem.collidesWithItem(host) == False:
overlapped = 0
if overlapped == 0:
hostItem_list.append(self.host_item.host_pixItem)
def mouseReleaseEvent(self, event):
global host_cs
if host_cs == 1:
if overlapped == 0:
self.addItem(self.host_item.host_pixItem)
self.host_item.host_pixItem.setPos(event.scenePos())
self.i += 1
host_list.append('h' + str(self.i))
class host_Object(QtGui.QGraphicsPixmapItem, QtGui.QWidget):
def __init__(self, parent=None):
super(host_Object, self).__init__(parent)
pixmap = QtGui.QPixmap("host.png")
self.host_pixItem = QtGui.QGraphicsPixmapItem(pixmap.scaled(30, 30, QtCore.Qt.KeepAspectRatio))
self.host_pixItem.setFlag(QtGui.QGraphicsPixmapItem.ItemIsSelectable)
self.host_pixItem.setFlag(QtGui.QGraphicsPixmapItem.ItemIsMovable)
class Form(QtGui.QMainWindow, QtGui.QWidget):
def __init__(self):
super(Form, self).__init__()
self.ui = uic.loadUi('form.ui')
self.ui.actionHost.triggered.connect(self.place_host)
self.scene = graphicsScene()
self.ui.view.setScene(self.scene)
def place_host(self):
host_cs = 1
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
form = Form()
form.ui.show()
app.exec_()
Multiple inheritance is source of all evil things in application design.
Also it is forbidden in Qt to double inherit QObject.
So all your classes with multiple inheritance has big flaws.
Even class host_Object(QtGui.QGraphicsPixmapItem, QtGui.QWidget) is wrong and problematic since item can't be a QWidget and QGraphicsItem at the same time.
I would recommend you to avoid double inheritance as a general rule not only for Qt framework but for any language.

Python - wxPython custom button -> unbound method __init__()? what?

After looking at questions like this it doesn't make sense that my __init__(self, parrent, id) would be throwing a unbound error? help?
main.py
import wx
from customButton import customButton
from wxPython.wx import *
class MyFrame(wx.Frame):
def __init__(self, parent, ID, title):
wxFrame.__init__(self, parent, ID, title,
wxDefaultPosition, wxSize(400, 400))
# Non-important code here...
# This is the first declaration of the Button1
# This is also where the ERROR is thrown.
# Omitting this line causes the window to execute
# flawlessly.
self.Button1 = customButton.__init__(self, parent, -1)
# ... finishes in a basic wx.program style...
customButton.py
# I've included all of the code in the file
# because have no idea where the bug/error happens
import wx
from wxPython.wx import *
class Custom_Button(wx.PyControl):
# The BMP's
Over_bmp = None #wxEmptyBitmap(1,1,1) # When the mouse is over
Norm_bmp = None #wxEmptyBitmap(1,1,1) # The normal BMP
Push_bmp = None #wxEmptyBitmap(1,1,1) # The down BMP
def __init__(self, parent, id, **kwargs):
wx.PyControl.__init__(self,parent, id, **kwargs)
# Set the BMP's to the ones given in the constructor
#self.Over_bmp = wx.Bitmap(wx.Image(MOUSE_OVER_BMP, wx.BITMAP_TYPE_ANY).ConvertToBitmap())
#self.Norm_bmp = wx.Bitmap(wx.Image(NORM_BMP, wx.BITMAP_TYPE_ANY).ConvertToBitmap())
#self.Push_bmp = wx.Bitmap(wx.Image(PUSH_BMP, wx.BITMAP_TYPE_ANY).ConvertToBitmap())
#self.Pos_bmp = self.pos
self.Bind(wx.EVT_LEFT_DOWN, self._onMouseDown)
self.Bind(wx.EVT_LEFT_UP, self._onMouseUp)
self.Bind(wx.EVT_LEAVE_WINDOW, self._onMouseLeave)
self.Bind(wx.EVT_ENTER_WINDOW, self._onMouseEnter)
self.Bind(wx.EVT_ERASE_BACKGROUND,self._onEraseBackground)
self.Bind(wx.EVT_PAINT,self._onPaint)
self._mouseIn = self._mouseDown = False
def _onMouseEnter(self, event):
self._mouseIn = True
def _onMouseLeave(self, event):
self._mouseIn = False
def _onMouseDown(self, event):
self._mouseDown = True
def _onMouseUp(self, event):
self._mouseDown = False
self.sendButtonEvent()
def sendButtonEvent(self):
event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
event.SetInt(0)
event.SetEventObject(self)
self.GetEventHandler().ProcessEvent(event)
def _onEraseBackground(self,event):
# reduce flicker
pass
def _onPaint(self, event):
dc = wx.BufferedPaintDC(self)
dc.SetFont(self.GetFont())
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
dc.DrawBitmap(self.Norm_bmp)
# draw whatever you want to draw
# draw glossy bitmaps e.g. dc.DrawBitmap
if self._mouseIn: # If the Mouse is over the button
dc.DrawBitmap(self, self.Mouse_over_bmp, self.Pos_bmp, useMask=False)
if self._mouseDown: # If the Mouse clicks the button
dc.DrawBitmap(self, self.Push_bmp, self.Pos_bmp, useMask=False)
You don't create an object like this:
self.Button1 = customButton.__init__(self, parent, -1)
you do it like this:
self.Button1 = customButton(parent, -1)
__init__ is an implicitly invoked method during object creation.
Don't call __init__() explicitly unless you know you need to.
self.Button1 = customButton(parent, -1)

Categories

Resources