How to use QStackedWidget() - python-3.x

Am trying to use QStackedWidget() to switch to my next window but when i do that i get some errors that don't have when i run my ".py" files separately.
what my app should do is ... activate my group box with a click, then if i click the button, a new transparent window should pop-up with a mouse-cross listener, then when you click something it should stops returning the mouse cursor to normal and closing the transparent window.
window1.py
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QColor, QKeySequence, QIcon, QCursor
from window2 import *
class Ui_Form(QtWidgets.QWidget):
def __init__(self):
super(Ui_Form, self).__init__()
##if i use this method, it does not show my transparent window, also it shows an error that i dont get when run it separately.
def goToTransparentWindowMethod(self):
self.goToTransparentWindow = TransparentWindowClass()
myWindow.addWidget(self.goToTransparentWindow)
myWindow.setCurrentIndex(myWindow.currentIndex()+1)
def setupUi(self, myWindow):
myWindow.setObjectName("myWindow")
myWindow.resize(627, 327)
self.horizontalLayoutWidget = QtWidgets.QWidget(myWindow)
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 300, 270))
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.gpb_main = QtWidgets.QGroupBox(self.horizontalLayoutWidget)
self.gpb_main.setCheckable(True)
self.gpb_main.setChecked(False)
self.gpb_main.setObjectName("gpb_spell_main")
self.btn_main = QtWidgets.QPushButton(self.gpb_main)
self.btn_main.setGeometry(QtCore.QRect(10, 40, 88, 27))
self.btn_main.setObjectName("btn_main")
self.btn_main.clicked.connect(self.goToTransparentWindowMethod)
self.horizontalLayout.addWidget(self.gpb_main)
self.retranslateUi(myWindow)
QtCore.QMetaObject.connectSlotsByName(myWindow)
def retranslateUi(self, myWindow):
_translate = QtCore.QCoreApplication.translate
myWindow.setWindowTitle(_translate("myWindow", "Window1"))
self.gpb_main.setTitle(_translate("myWindow", "example"))
self.btn_main.setText(_translate("myWindow", "click me"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
myWindow = QtWidgets.QStackedWidget()
ui = Ui_Form()
ui.setupUi(myWindow)
myWindow.show()
sys.exit(app.exec_())
window2.py
from PyQt5 import QtCore, QtGui, QtWidgets
from pynput.mouse import Listener
import pyautogui
class TransparentWindowThreadClass(QtCore.QObject):
def __init__(self, parent=None):
super(TransparentWindowThreadClass, self).__init__()
#QtCore.pyqtSlot()
def on_click_main(self, x, y, button, pressed):
try:
if pressed:
self.pos_main = pyautogui.position()
self.get_rgb_main = pyautogui.pixel(self.pos_main[0], self.pos_main[1])
r = self.get_rgb_main.red
g = self.get_rgb_main.green
b = self.get_rgb_main.blue
self.get_rgb_main = r,g,b
Transparent_Window.unsetCursor()#error here when is called from window1
Transparent_Window.close()#error here when is called from window1
#Pressed
self.pressed_Msg = 'Pressed at x:{0} y:{1} RGB:{2}'.format(x, y, self.get_rgb_main)
print(self.pressed_Msg)
else:
#Released msg
self.released_Msg = 'Released at x:{0} y:{1} RGB:{2}'.format(x, y, self.get_rgb_main)
print(self.released_Msg)
if not pressed:
return False
except KeyboardInterrupt:
print('you pressed ctrl+c')
except NameError:
print("Error on_click_main")
except RuntimeError:
print('run time error')
except TypeError:
print('ype error')
except AttributeError:
print('Attribute Error')
#QtCore.pyqtSlot()
def loop_onclick_listener(self):
try:
with Listener(on_click=self.on_click_main) as listener:
listener.join()
except KeyboardInterrupt:
print('you pressed ctrl+c')
except NameError:
print("Error onclick_listener")
except RuntimeError:
print('run time error')
except TypeError:
print('ype error')
except AttributeError:
print('Attribute Error')
class TransparentWindowClass(QtWidgets.QWidget):
def __init__(self, parent=None):
super(TransparentWindowClass, self).__init__()
self.monitorResolution = pyautogui.size()
# create a QThread and start the thread that handles
self.thread = QtCore.QThread()
self.thread.start()
# create the worker without a parent so you can move it
self.worker = TransparentWindowThreadClass()## my custom thread class
# the worker is moved to another thread
self.worker.moveToThread(self.thread)
# if the thread started, connect it
self.thread.started.connect(self.worker.loop_onclick_listener)
def setupUi(self, Transparent_Window):
Transparent_Window.setObjectName("Transparent_Window")
Transparent_Window.resize(self.monitorResolution[0], self.monitorResolution[1])
Transparent_Window.setWindowFlags(QtCore.Qt.FramelessWindowHint)
Transparent_Window.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
Transparent_Window.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
self.retranslateUi(Transparent_Window)
QtCore.QMetaObject.connectSlotsByName(Transparent_Window)
def retranslateUi(self, Transparent_Window):
_translate = QtCore.QCoreApplication.translate
Transparent_Window.setWindowTitle(_translate("Transparent", "Transparent Window"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Transparent_Window = QtWidgets.QWidget()
ui = TransparentWindowClass()
ui.setupUi(Transparent_Window)
Transparent_Window.show()
sys.exit(app.exec_())

You are making things too complex.
Also, even assuming that no other possible solution could be used, you must remember that widgets are not thread-safe, and can not be directly accessed from external threads. The only safe and correct way to communicate between threads is by using signals and slots.
That said, there is no need for pyautogui nor pynput if you just want to get the color of a pixel on the screen.
If you want to grab a pixel on the screen, you can use the QScreen function grabWindow(), using 0 as window id (which matches the whole screen), and with a single-pixel area.
Then you can use grabMouse() to ensure that you always receive mouse events, even if the mouse is outside of the widget and no mouse button was being pressed. Note that grabMouse() can only work on visible widgets, so we need to "hide" the window by moving it off-screen.
Then, overriding mousePressEvent() you can use grabWindow() with the global position of the mouse, it will return a QPixmap that can be converted to a QImage and get the pixelColor() of the grab above.
The grabbing can be canceled by pressing Esc.
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class GrabTest(QWidget):
def __init__(self):
super().__init__()
self.resize(200, 200)
self.button = QPushButton('Grab!')
self.colorLabel = QLabel('No color', alignment=Qt.AlignCenter)
self.colorLabel.setFixedSize(120, 30)
self.colorLabel.setStyleSheet('border: 1px solid black;')
layout = QVBoxLayout(self)
layout.addStretch()
layout.addWidget(self.button, alignment=Qt.AlignCenter)
layout.addWidget(self.colorLabel, alignment=Qt.AlignCenter)
layout.addStretch()
self.button.clicked.connect(self.startGrab)
def mousePressEvent(self, event):
if QWidget.mouseGrabber() == self:
self.getPixel(event.globalPos())
else:
super().mousePressEvent(event)
def keyPressEvent(self, event):
if QWidget.mouseGrabber() == self and event.key() == Qt.Key_Escape:
self.stopGrab()
else:
super().keyPressEvent(event)
def startGrab(self):
self.grabMouse(Qt.CrossCursor)
self.oldPos = self.pos()
deskRect = QRect()
for screen in QApplication.screens():
deskRect |= screen.geometry()
# move the window off screen while keeping it visible
self.move(deskRect.bottomRight())
def stopGrab(self):
self.releaseMouse()
self.move(self.oldPos)
def getPixel(self, pos):
screen = QApplication.screens()[0]
pixmap = screen.grabWindow(0, pos.x(), pos.y(), 1, 1)
color = pixmap.toImage().pixelColor(0, 0)
if color.lightnessF() > .5:
textColor = 'black'
else:
textColor = 'white'
self.colorLabel.setStyleSheet('''
color: {};
background: {};
'''.format(textColor, color.name()))
self.colorLabel.setText(color.name())
self.stopGrab()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
grabber = GrabTest()
grabber.show()
sys.exit(app.exec())

Related

How to use QtWebEngine createWindow in PyQt5

I am trying to make a window that contains a QWebEngineView. Now I want the browser to be able to handle the create window or _blank type triggers, or specifically to open a URL in a new window when required. In the below code, when there is requirement to create a window by the browser, createwindow() is called, but that doesn't open the window. Please help me with the correct way to open a new window by the browser when required in the below case.
import json
import sys
import os
import time
import json
import sys
import platform
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
from PyQt5.QtWebEngineWidgets import QWebEngineSettings as QWebSettings
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtCore import QUrl
from main_dash import Ui_MainWindow
class MainDashWindow(QMainWindow):
socketSignal = QtCore.pyqtSignal(object) # must be defined in class level
def __init__(self):
QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
# self.ui.setupUi(self)
# ui = Ui_MainWindow()
self.isMax = 0
self.ui.setupUi(self)
def re_setup(self):
self.page = WebEnginePage2()
self.page.Notifications = True
self.ui.full_content_container.hide()
self.page.createWindow = True
self.page.settings().setAttribute(QWebSettings.JavascriptEnabled, True)
self.page.settings().setAttribute(QWebSettings.JavascriptCanOpenWindows, True)
self.page.settings().setAttribute(
QWebSettings.JavascriptCanAccessClipboard, True)
# self.full_content_container is the webengineview in the mainUi file
self.ui.full_content_container.setPage(self.page)
# self.ui.full_content_container.setContextMenuPolicy(Qt.NoContextMenu)
url6 = "...../icons_nec/ui/index.html"
self.ui.full_content_container.setUrl(QtCore.QUrl(url6))
self.ui.full_content_container.loadFinished.connect(
self.on_load_finished)
########################################################################
self.show()
## ==> END ##
def get_path(self, filename):
if hasattr(sys, "_MEIPASS"):
return f'{os.path.join(sys._MEIPASS, filename)}'
else:
return f'{filename}'
def on_load_finished(self):
self.ui.full_content_container.show()
class WebEnginePage2(QWebEnginePage):
def __init__(self, *args, **kwargs):
QWebEnginePage.__init__(self, *args, **kwargs)
self.featurePermissionRequested.connect(
self.onFeaturePermissionRequested)
def onFeaturePermissionRequested(self, url, feature):
self.setFeaturePermission(
url, feature, QWebEnginePage.PermissionGrantedByUser)
def createWindow(self,
wintype: QWebEnginePage.WebWindowType) -> QWebEngineView:
"""Called by Qt when a page wants to create a new tab or window.
In case the user wants to open a resource in a new tab, we use the
createWindow handling of the main page to achieve that.
See WebEngineView.createWindow for details.
"""
return self.page().inspectedPage().view().createWindow(wintype)
# Store external windows.
external_windows = []
def acceptNavigationRequest(self, url, _type, isMainFrame):
print("in navigation")
if _type == QWebEnginePage.NavigationTypeLinkClicked:
w = QWebEngineView()
w.setUrl(url)
w.show()
print("link detected")
# Keep reference to external window, so it isn't cleared up.
self.external_windows.append(w)
return False
# QDesktopServices.openUrl(url)
# elif _type == QWebEnginePage.NavigationType
return super().acceptNavigationRequest(url, _type, isMainFrame)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainDashWindow()
window.re_setup()
sys.exit(app.exec_())
Here is the Ui_MainWindow file, which is being imported above.
I need to figure out with such a scenario how can I implement createWindow() if required by websites.
from PyQt5 import QtWebEngineWidgets
import all_icons_rc
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1280, 720)
MainWindow.setMinimumSize(QtCore.QSize(1280, 720))
MainWindow.setMaximumSize(QtCore.QSize(1920, 1080))
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_2.setSpacing(0)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.Header = QtWidgets.QFrame(self.centralwidget)
self.Header.setMinimumSize(QtCore.QSize(0, 40))
self.Header.setMaximumSize(QtCore.QSize(16777215, 50))
self.Header.setStyleSheet("background-color: rgb(33, 37, 41);")
self.Header.setFrameShape(QtWidgets.QFrame.NoFrame)
self.Header.setFrameShadow(QtWidgets.QFrame.Raised)
self.Header.setObjectName("Header")
self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.Header)
self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_4.setSpacing(0)
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.frame_2 = QtWidgets.QFrame(self.Header)
self.frame_2.setStyleSheet("")
self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_2.setObjectName("frame_2")
self.horizontalLayout_4.addWidget(self.frame_2)
self.frame = QtWidgets.QFrame(self.Header)
self.frame.setMaximumSize(QtCore.QSize(150, 16777215))
self.frame.setStyleSheet("/*background-color: rgb(85, 255, 0);*/")
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame)
self.horizontalLayout.setSpacing(15)
self.horizontalLayout.setObjectName("horizontalLayout")
self.minimize_btn = QtWidgets.QPushButton(self.frame)
self.minimize_btn.setText("")
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(
":/icons/Icons/icons8_macos_minimize_50px.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.minimize_btn.setIcon(icon)
self.minimize_btn.setIconSize(QtCore.QSize(30, 30))
self.minimize_btn.setFlat(True)
self.minimize_btn.setObjectName("minimize_btn")
self.horizontalLayout.addWidget(self.minimize_btn)
self.maximize_btn = QtWidgets.QPushButton(self.frame)
self.maximize_btn.setText("")
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(
":/icons/Icons/icons8_maximize_window_50px.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.maximize_btn.setIcon(icon1)
self.maximize_btn.setIconSize(QtCore.QSize(30, 30))
self.maximize_btn.setFlat(True)
self.maximize_btn.setObjectName("maximize_btn")
self.horizontalLayout.addWidget(self.maximize_btn)
self.close_btn = QtWidgets.QPushButton(self.frame)
self.close_btn.setText("")
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(
":/icons/Icons/icons8_Close_50px_2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.close_btn.setIcon(icon2)
self.close_btn.setIconSize(QtCore.QSize(30, 30))
self.close_btn.setFlat(True)
self.close_btn.setObjectName("close_btn")
self.horizontalLayout.addWidget(self.close_btn)
self.horizontalLayout_4.addWidget(self.frame)
self.verticalLayout_2.addWidget(self.Header)
self.body = QtWidgets.QFrame(self.centralwidget)
self.body.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.body.setFrameShadow(QtWidgets.QFrame.Raised)
self.body.setLineWidth(0)
self.body.setObjectName("body")
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.body)
self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_3.setSpacing(0)
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.full_content_container = QtWebEngineWidgets.QWebEngineView(
self.body)#<----This is webengineview
self.full_content_container.setStyleSheet("background-color: rgb(85, 255, 255);\n"
"border:none;")
self.full_content_container.setObjectName("full_content_container")
self.verticalLayout_3.addWidget(self.full_content_container)
self.verticalLayout_2.addWidget(self.body)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
For now, just Ignore the icons.
index.html file snippet which is being loaded in webengineview for testing
<!DOCTYPE html>
<html>
<body>
<h1>The a target attribute</h1>
<p>Open link in a new window or tab: Visit PathOr!</p>
</body>
</html>
UPDATE:
Below is an implementaion based on your example code. Everything should work as expected if you completely replace your WebEnginePage2 class with this one:
class WebEnginePage2(QWebEnginePage):
_windows = {}
#classmethod
def newWindow(cls):
window = QWebEngineView()
window.setObjectName(f'window-{id(window)}')
window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
window.destroyed.connect(
lambda window: cls._windows.pop(window.objectName(), None))
window.setPage(cls(window))
cls._windows[window.objectName()] = window
return window
def __init__(self, *args, **kwargs):
QWebEnginePage.__init__(self, *args, **kwargs)
self.featurePermissionRequested.connect(
self.onFeaturePermissionRequested)
self.geometryChangeRequested.connect(self.handleGeometryChange)
def handleGeometryChange(self, rect):
view = self.view()
window = QtGui.QWindow.fromWinId(view.winId())
if window is not None:
rect = rect.marginsRemoved(window.frameMargins())
view.resize(rect.size())
view.show()
def createWindow(self, mode):
window = self.newWindow()
if mode != QtWebEngineWidgets.QWebEnginePage.WebDialog:
window.resize(800, 600)
window.show()
return window.page()
def onFeaturePermissionRequested(self, url, feature):
self.setFeaturePermission(
url, feature, QWebEnginePage.PermissionGrantedByUser)
You need to create a new instance of the browser window and keep a reference to it in a window list. It's also important to ensure the window is given an appropriate size, otherwise it won't be visible. For windows opened with javascript, the geometryChangeRequested signal can be used to set the requested size, otherwise a default should be used.
Below is a simple demo that implements the basic features. Hopefully it should be obvious how to adapt this to your own application:
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets
class Browser(QtWebEngineWidgets.QWebEngineView):
_windows = set()
#classmethod
def _removeWindow(cls, window):
cls._windows.discard(window)
#classmethod
def newWindow(cls):
window = cls()
cls._windows.add(window)
return window
def __init__(self, parent=None):
super().__init__(parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
self.page().geometryChangeRequested.connect(self.handleGeometryChange)
self.page().titleChanged.connect(self.setWindowTitle)
def closeEvent(self, event):
self._removeWindow(self)
event.accept()
def handleGeometryChange(self, rect):
window = QtGui.QWindow.fromWinId(self.winId())
if window is not None:
rect = rect.marginsRemoved(window.frameMargins())
self.resize(rect.size())
self.setFocus()
self.show()
def createWindow(self, mode):
window = self.newWindow()
if mode != QtWebEngineWidgets.QWebEnginePage.WebDialog:
window.resize(800, 600)
window.show()
return window
html = """
<html><head><title>Test Page</title>
<script type="text/javascript"><!--
var count = 0
var url = 'https://www.google.com'
function newWindow() {
count += 1
window.open(url, 'Test' + count, 'width=640,height=480');
}
--></script>
</head>
<body>
<input type="button" value="New Window" onclick="newWindow()" />
<p>Blank</p>
</body>
</html>"""
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
browser = Browser()
browser.setHtml(html)
browser.setGeometry(600, 100, 400, 200)
browser.show()
sys.exit(app.exec_())

How to remove all widgets within a QGroupBox in PyQt5?

In my program there is a QGroupBox displayed that has many QPushButton's within it. During the execution of the program, the user can click a button outside of the QGroupBox and all of the buttons within it will be removed or hidden. Problem is that I can't seem to find a way to do this to the buttons directly or by clearing the QGroupBox.
I have already tried deleteLater on the buttons but that didn't work. I then tried clearing the layout of the QGroupBox but that didn't work either. Here is some code I just wrote up that has a the same problem:
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
import random
class UI_Dialog(object):
def addButtons(self,looping):
# Code to remove the previous QPushButton's goes here.
placement = -100
for i in range(looping):
currentName = 'btn' + str(i)
placement = placement + 110
self.btnB = QtWidgets.QPushButton(self.groupBox)
self.btnB.setGeometry(QtCore.QRect(10+placement, 30+placement, 100, 100))
self.btnB.show()
self.btnB.setObjectName(currentName)
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(1300, 800)
self.btnA = QtWidgets.QPushButton(Dialog)
self.btnA.setGeometry(QtCore.QRect(10, 80, 101, 131))
self.btnA.setObjectName("btn1")
self.btnA.clicked.connect(self.pushed)
self.formLayout = QtWidgets.QFormLayout()
self.groupBox = QtWidgets.QGroupBox("Results")
self.groupBox.setLayout(self.formLayout)
self.resultScrollArea = QtWidgets.QScrollArea(Dialog)
self.resultScrollArea.setWidget(self.groupBox)
self.resultScrollArea.setGeometry(QtCore.QRect(20, 220, 1011, 531))
self.resultScrollArea.setWidgetResizable(True)
self.resultScrollArea.setObjectName("resultScrollArea")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def pushed(self):
unkownLength = random.randint(1,20)
self.addButtons(unkownLength)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Example Program"))
self.btnA.setText(_translate("Dialog", "Push Button"))
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = UI_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
There are things here that probably don't make sense like the window size, the multiple function calls or it being a Dialog window instead of a QMainWindow. However, in the context of the actual program they do make sense so just ignore that, I know it's inefficient. Also the whole point of the unkownLength variable is to emulate that in the actual program, the number of buttons generated will be determined by user input. The buttons must also not be there at the start so that is why they're created with a button click. When the button is clicked again it should remove or hide all the buttons it created before. Any ideas?
Taking advantage that the buttons are children of the QGroupBox we can get the buttons using findChildren() to use deleteLater():
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
import random
class UI_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(1300, 800)
self.btnA = QtWidgets.QPushButton(Dialog)
self.btnA.setGeometry(QtCore.QRect(10, 80, 101, 131))
self.btnA.setObjectName("btn1")
self.formLayout = QtWidgets.QFormLayout()
self.groupBox = QtWidgets.QGroupBox("Results")
self.groupBox.setLayout(self.formLayout)
self.resultScrollArea = QtWidgets.QScrollArea(Dialog)
self.resultScrollArea.setWidget(self.groupBox)
self.resultScrollArea.setGeometry(QtCore.QRect(20, 220, 1011, 531))
self.resultScrollArea.setWidgetResizable(True)
self.resultScrollArea.setObjectName("resultScrollArea")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Example Program"))
self.btnA.setText(_translate("Dialog", "Push Button"))
class Dialog(QtWidgets.QDialog, UI_Dialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setupUi(self)
self.btnA.clicked.connect(self.pushed)
#QtCore.pyqtSlot()
def pushed(self):
unkownLength = random.randint(1, 20)
self.addButtons(unkownLength)
def addButtons(self, looping):
for button in self.groupBox.findChildren(QtWidgets.QPushButton):
button.deleteLater()
placement = -100
pos = QtCore.QPoint(20, 40)
for i in range(looping):
currentName = "btn" + str(i)
self.btnB = QtWidgets.QPushButton(
self.groupBox, objectName=currentName
)
self.btnB.setGeometry(QtCore.QRect(pos, QtCore.QSize(100, 100)))
pos += QtCore.QPoint(110, 110)
self.btnB.show()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Dialog()
w.show()
sys.exit(app.exec_())

PyQt5 - How to draw a dot on mouse click position?

I am trying to draw a dot on my main window, but the dot is not shown.
I've tried bounding mousePressEvent to paintEvent, but it didn't work as well. Here's current version of my code(which is not working too). Also I tried place a point with drawPoint method and it didn't work too.
import sys
from PyQt5 import QtWidgets, QtGui, QtCore, uic
class GUI(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi('gui.ui', self)
self.setFixedSize(self.size())
self.show()
def mousePressEvent(self, e):
print(e.pos())
qp = QtGui.QPainter()
qp.begin(self)
qp.setPen(QtCore.Qt.red)
qp.drawEllipse(e.pos().x(), e.pos().y(), 10, 10)
qp.end()
self.update()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = GUI()
sys.exit(app.exec_())
I know that mousePressEvent is working since I get coords of the click.
I am okay to change methods of dot-placing or type of dots to place, but it should have customizable color and size.
You should only draw within the paintEvent method, and this paint does not save memory so if you want to graph several points you must store them in some container, for example using QPolygon.
paintEvent() is called every time you call update() or repaint(), for example it is called every time it is resized, the window is moved, etc.
import sys
from PyQt5 import QtWidgets, QtGui, QtCore, uic
class GUI(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi('gui.ui', self)
self.setFixedSize(self.size())
self.show()
self.points = QtGui.QPolygon()
def mousePressEvent(self, e):
self.points << e.pos()
self.update()
def paintEvent(self, ev):
qp = QtGui.QPainter(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing)
pen = QtGui.QPen(QtCore.Qt.red, 5)
brush = QtGui.QBrush(QtCore.Qt.red)
qp.setPen(pen)
qp.setBrush(brush)
for i in range(self.points.count()):
qp.drawEllipse(self.points.point(i), 5, 5)
# or
# qp.drawPoints(self.points)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = GUI()
sys.exit(app.exec_())

pyqt5: why the mimeData().text() returns nothing?

learning PyQt5 recently, I've tried to drag a QPushButton learning this tutorial Drag & drop a button widget, and made some improvements to place the button more accurate, so I add
mime = e.mimeData().text()
x, y = mime.split(',')
according to #Avaris for this question, but I found e.mimeData().text() returned nothing which supposed to be the coordinate of local position of the cursor with respect to the button, i tried to print(mime), and got a blank line with nothing, then i print(mime.split(',')) and got ['']。
here's the code:
import sys
from PyQt5.QtWidgets import QPushButton, QWidget, QApplication, QLabel
from PyQt5.QtCore import Qt, QMimeData
from PyQt5.QtGui import QDrag
from PyQt5 import QtCore
class Button(QPushButton):
def __init__(self, title, parent):
super().__init__(title, parent)
def mouseMoveEvent(self, e):
if e.buttons() != Qt.RightButton:
return
mimeData = QMimeData()
drag = QDrag(self)
drag.setMimeData(mimeData)
dropAction = drag.exec_(Qt.MoveAction)
def mousePressEvent(self, e):
QPushButton.mousePressEvent(self, e)
if e.button() == Qt.LeftButton:
print('press')
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setAcceptDrops(True)
self.button = Button('Button', self)
self.button.move(100, 65)
self.setWindowTitle('Click or Move')
self.setGeometry(300, 300, 280, 150)
def dragEnterEvent(self, e):
e.accept()
def dropEvent(self, e):
position = e.pos()
mime = e.mimeData().text()
x, y = mime.split(',')
#print(mime.split(','))
self.button.move(position - QtCore.QPoint(int(x), int(y)))
e.setDropAction(Qt.MoveAction)
e.accept()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
ex.show()
app.exec_()
In the answer of #Avaris, you will notice they set the mimedata with the button position in the mouseMoveEvent:
mimeData = QtCore.QMimeData()
# simple string with 'x,y'
mimeData.setText('%d,%d' % (e.x(), e.y()))
The mimedata does not contain anything by default. You have to set everything yourself! Have a look at the documentation for QMimeData to see what else you can do (other than setting arbitrary text)
Drag and Drop in Camera View
def dragEnterEvent(self, event): # Drag lines
mimeData = QtCore.QMimeData()
if mimeData.hasText:
event.accept()
else:
event.ignore()
def dropEvent(self, event): # Drop lines
mimeData = QtCore.QMimeData()
format = 'application/x-qabstractitemmodeldatalist'
data=event.mimeData().data(format) # Drag Drop get data's name
name_str = codecs.decode(data,'utf-8') # Convert byte to string
mimeData.setText(name_str)
# print(name_str[26:].replace('\x00','').strip("")) # remove white space
if mimeData.hasText:
print(name_str)
# write what you will do

PyQt4 Mdi sub window not resizing properly

In the following example, when you click the button, the entire form is rebuilt adding a new label each time. At the end is a resize call that doesn't appear to work. While debugging, I validated the sizeHint() is returning the correct dimensions, and internally the widget thinks it is the correct size, but what is drawn is not correct. What can I do to force the MDI window to resize correctly? Also of note, when not sized correctly, if you manually start resizing, it suddenly snaps to the appropriate size.
import sys
import os
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import PyQt4.Qt
class MdiWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.count = 0
self.buildWindow()
def buildWindow(self):
main = QVBoxLayout()
button = QPushButton('Change Count')
button.clicked.connect(self.changeCount)
main.addWidget(button)
for i in range(self.count):
main.addWidget(QLabel(str(i)))
widget = QWidget()
widget.setLayout(main)
self.setCentralWidget(widget)
self.resize(main.sizeHint())
def changeCount(self, event):
self.count += 1
self.buildWindow()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('Resize Test')
self.mdiArea = QMdiArea()
self.setCentralWidget(self.mdiArea)
child = MdiWindow()
self.mdiArea.addSubWindow(child)
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit(app.exec_())

Resources