How make application desktop toolbar UI with PyQT5 - python

How make/register UI as an Application Desktop Toolbar (Windows) to prevent other applications from using the desktop area used by UI? Need to create custom taskbar-like panel at bottom, and that the rest of the windows fit into the size, not under ui.

At least i find question from wxappbars and appbar. After some adaptation to PyQt5 it worked for me.
"""
Registering an Application Desktop Toolbar in Windows for PyQt5 window.
Taken from https://gist.github.com/swdevbali/495f902162446b30cd567b2a44d86d79 and
https://github.com/sabren/ceomatic/blob/master/wxappbars.py,
thanks for swdevbali and sabren
Adapted by Elendiar.
"""
import ctypes, sys
from ctypes import wintypes
from ctypes import *
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QDesktopWidget, QWidget
from PyQt5.QtCore import *
from copy import deepcopy
shell32 = windll.shell32
user32 = windll.user32
import win32api, win32con, win32gui
class APPBARDATA(Structure):
_fields_= [
("cbSize", wintypes.DWORD),
("hWnd", wintypes.HWND),
("uCallbackMessage", ctypes.c_ulong),
("uEdge", c_ulong),
("rc", wintypes.RECT),
("lParam", wintypes.LPARAM),
]
PAPPBARDATA = POINTER(APPBARDATA)
class ABEdge:
Left = 0
Top = 1
Right = 2
Bottom = 3
Float = 4
class ABMsg:
ABM_NEW = 0
ABM_REMOVE = 1
ABM_QUERYPOS = 2
ABM_SETPOS = 3
ABM_GETSTATE = 4
ABM_GETTASKBARPOS = 5
ABM_ACTIVATE = 6
ABM_GETAUTOHIDEBAR = 7
ABM_SETAUTOHIDEBAR = 8
ABM_WINDOWPOSCHANGED = 9
ABM_SETSTATE = 10
class ABNotify:
ABN_STATECHANGE = 0
ABN_POSCHANGED = 1
ABN_FULLSCREENAPP = 2
ABN_WINDOWARRANGE = 3
class RegisterInfo(object):
def __init__(self):
self._window = None
self.callbackId = 0
self.isRegistered = False
self.edge = ABEdge.Float
self.originalStyle = None
self.originalPosition = None
self.originalSize = None
self.originalResizeMode = None
#property
def window(self):
return self._window
#window.setter
def window(self, window):
self._window = window
self._hWnd = window.winId().__int__()
self._oldWndProc = win32gui.SetWindowLong(self._hWnd,
win32con.GWL_WNDPROC,
self.WndProc)
# http://wiki.wxpython.org/HookingTheWndProc
def WndProc(self, hWnd, msg, wParam, lParam ):
if msg == win32con.WM_DESTROY:
self._restoreOldWndProc()
elif msg == self.callbackId:
if wParam == ABNotify.ABN_POSCHANGED:
_ABSetPos(self.edge, self.window)
else:
return win32gui.\
CallWindowProc(self._oldWndProc, hWnd, msg, wParam, lParam)
def _restoreOldWndProc(self):
win32api.SetWindowLong(self._hWnd,
win32con.GWL_WNDPROC,
self._oldWndProc)
_registeredWindowInfo = {}
def _GetRegisterInfo(appbarWindow):
geometry = appbarWindow.geometry()
reg = RegisterInfo()
reg.callBackId = 0
reg.window = appbarWindow
reg.isRegistered = False
reg.edge = ABEdge.Top
reg.originalStyle = appbarWindow.windowFlags()
reg.originalPosition = QPoint(geometry.x(), geometry.y())
reg.originalSize = QSize(geometry.width(), geometry.height())
_registeredWindowInfo[appbarWindow] = reg
return _registeredWindowInfo[appbarWindow]
def _RestoreWindow(appbarWindow):
info = _GetRegisterInfo(appbarWindow)
appbarWindow.setWindowFlags(info.originalStyle)
appbarWindow.move(info.originalPosition)
appbarWindow.resize(info.originalSize)
def SetAppBar(appbarWindow, edge, barSize):
info = _GetRegisterInfo(appbarWindow)
info.edge = edge
abd = APPBARDATA()
abd.cbSize = wintypes.DWORD(sizeof(abd))
abd.hWnd = wintypes.HWND(appbarWindow.winId().__int__())
if (edge == ABEdge.Float) and info.isRegistered:
shell32.SHAppBarMessage(ABMsg.ABM_REMOVE, PAPPBARDATA(abd))
info.isRegistered = False
_RestoreWindow(appbarWindow)
elif not info.isRegistered:
info.isRegistered = True
info.callbackId = win32api.RegisterWindowMessage("AppBarMessage")
shell32.SHAppBarMessage(ABMsg.ABM_NEW, PAPPBARDATA(abd))
appbarWindow.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
_ABSetPos(info.edge, appbarWindow, barSize)
def RemoveAppBar(appbarWindow):
print('REMOVING')
info = _GetRegisterInfo(appbarWindow)
abd = APPBARDATA()
shell32.SHAppBarMessage(ABMsg.ABM_REMOVE, PAPPBARDATA(abd))
info.isRegistered = False
#_RestoreWindow(appbarWindow)
def _DoResize(appBarWindow, rect):
appBarWindow.resize(rect.Width, rect.Height)
appBarWindow.move(rect.Left, rect.Top)
def _ABSetPos(edge, appbarWindow, barSize):
barData = APPBARDATA()
barData.cbSize = wintypes.DWORD(sizeof(barData))
barData.hWnd = appbarWindow.winId().__int__()
barData.uEdge = edge
screen = QDesktopWidget().screenGeometry()
deskW = screen.width()
deskH = screen.height()
if barData.uEdge == ABEdge.Left or barData.uEdge == ABEdge.Right:
winW = barSize
winH = deskH
barData.rc.top = 0
barData.rc.bottom = deskH
if barData.uEdge == ABEdge.Left:
barData.rc.left = 0
barData.rc.right = winW
else:
barData.rc.right = deskW
barData.rc.left = deskW - winW
else:
winW = deskW
winH = barSize
barData.rc.left = 0
barData.rc.right = deskW
if barData.uEdge == ABEdge.Top:
barData.rc.top = 0
barData.rc.bottom = winH
else:
barData.rc.bottom = deskH
barData.rc.top = deskH - winH
oldLeft = deepcopy(barData.rc.left) # deepcopy because after reopen x from 0
become w -> 222 and window isnt visible.
shell32.SHAppBarMessage(ABMsg.ABM_QUERYPOS, PAPPBARDATA(barData))
shell32.SHAppBarMessage(ABMsg.ABM_SETPOS, PAPPBARDATA(barData))
barData.rc.left = deepcopy(oldLeft)
def _resize():
x = barData.rc.left
y = barData.rc.top
w = barData.rc.right - barData.rc.left
h = barData.rc.bottom - barData.rc.top
appbarWindow.resize(w, h)
appbarWindow.move(x, y)
# This is done async, because windows will send a resize after a new appbar is
added.
# if we size right away, the windows resize comes last and overrides us.
QTimer.singleShot(300, _resize)
if __name__=="__main__":
# DPI scaling
# QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
# QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
app = QtWidgets.QApplication(sys.argv)
win = QWidget()
win.setWindowFlags(Qt.FramelessWindowHint |
Qt.WindowStaysOnTopHint |
Qt.CustomizeWindowHint |
Qt.Tool
)
btn = QtWidgets.QPushButton('Click-to-close', win)
btn.clicked.connect(QtWidgets.qApp.quit)
barSize = 222
SetAppBar(win, ABEdge.Left, barSize)
win.show()
sys.exit(app.exec_())

Related

How to stop my program in raspberry with thread?

I have a project to build GUI for raspberry project thermocycler. I have some error in pushbutton GUI. I can start the thermocycler from pushbutton GUI, but can't to stop. When thermocycler is on, my GUI freeze. I will write my code below. If anyone have a solution for my error please. what is need use a threading?
my code
import sys
from PySide2 import *
from PySide2.QtGui import QPainter
from PySide2.QtWidgets import (QMainWindow, QApplication)
from PySide2.QtCharts import QtCharts
from PySide2.QtGui import QPainter
from PySide2.QtWidgets import (QMainWindow, QApplication)
from PySide2.QtCharts import QtCharts
from random import randrange
from functools import partial
import csv
import time
import math
import RPi.GPIO as GPIO
import Adafruit_ADS1x15
from datetime import datetime
file_date = datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
from ui_interface4 import 4
shadow_elements = {
"left_menu_frame",
"frame_3",
"frame_5",
"header_frame",
"frame_9"
}
temp_denat = 95
temp_anel = 55
temp_exten = 72
temp_refri = 4
heat_pin = 19 #pwm > GPIO 19 > LPWM
cool_pin = 18 #pwm > GPIO 13 > RPWM
pwm_fan = 12 #pwm > GPIO 12 > fan cooling
low_volt = 21 #digital > GPIO 21 > 3v3
class MainWindow(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.shadow = QGraphicsDropShadowEffect(self)
self.shadow.setBlurRadius(20)
self.shadow.setXOffset(0)
self.shadow.setYOffset(0)
self.ui.centralwidget.setGraphicsEffect(self.shadow)
self.setWindowIcon(QtGui.QIcon(":/icons/icons/pie-chart.svg"))
self.setWindowTitle("PCR_2")
QSizeGrip(self.ui.size_grip)
self.ui.minimize_window_button.clicked.connect(lambda: self.showMinimized())
self.ui.close_window_button.clicked.connect(lambda: self.close())
self.ui.restore_window_button.clicked.connect(lambda: self.restore_or_maximize_window())
switch = False
def Program_Run (switch):
def suhu_c(R, Ro=100000.0, To=25.0, beta=3950.0):
suhu = math.log(R / Ro)
suhu /= beta
suhu += 1.0 / (To + 273.15)
suhu = (1.0 / suhu)
suhu -=273.15
return suhu
GPIO.setwarnings(False) #disable warning
GPIO.setmode(GPIO.BCM) #board GPIO
GPIO.setup(heat_pin,GPIO.OUT)
GPIO.setup(cool_pin,GPIO.OUT)
GPIO.setup(pwm_fan,GPIO.OUT)
GPIO.setup(low_volt,GPIO.OUT)
GPIO.output(low_volt,GPIO.HIGH)
adc = Adafruit_ADS1x15.ADS1115(address=0x49,busnum=1)
GAIN = 2/3
t = 0
rn = 100000
pwm_val = 0
print('channel-0 value')
told = time.time()
cool = GPIO.PWM(heat_pin,490) #490Hz
heat = GPIO.PWM(cool_pin,490) #490Hz
fan = GPIO.PWM(pwm_fan,490) #490Hz
heat.start(0)
cool.start(0)
fan.start(0)
while switch == True:
range = time.time() - told
bit = adc.read_adc_difference(0,gain=GAIN)
voltage = (bit*6.144)/32768
R = rn*((5*rn)-(voltage*2*rn))/((5*rn)+(voltage*2*rn))
suhu = suhu_c(R)
if suhu <= temp_denat:
pwm = 96
cool.ChangeDutyCycle(0)
heat.ChangeDutyCycle(pwm)
fan.ChangeDutyCycle(0)
if suhu >= temp_denat:
pwm = 80
cool.ChangeDutyCycle(pwm)
heat.ChangeDutyCycle(0)
fan.ChangeDutyCycle(100)
if range >= 1.00:
print(t,' ADC bit:',round(bit),' bit', ',voltage: ',round(voltage,3),' volt','suhu', round(suhu,3), ' C','R:',round(R,3),'ohm')
t += 1
told = time.time()
while switch == False:
break
def Start_Program():
switch = True
Program_Run (switch)
def Stop_Program():
switch = False
Program_Run (switch)
def moveWindow(e):
if self.isMaximized() == False: #Not maximized
if e.buttons() == Qt.LeftButton:
self.move(self.pos() + e.globalPos() - self.clickPosition)
self.clickPosition = e.globalPos()
e.accept()
self.ui.header_frame.mouseMoveEvent = moveWindow
self.show()
for x in shadow_elements:
## # Shadow effect style
effect = QtWidgets.QGraphicsDropShadowEffect(self)
effect.setBlurRadius(18)
effect.setXOffset(0)
effect.setYOffset(0)
effect.setColor(QColor(0, 0, 0, 255))
getattr(self.ui, x).setGraphicsEffect(effect)
self.ui.START_btn.clicked.connect(Start_Program)
self.ui.CANCEL_btn.clicked.connect(Stop_Program)
def restore_or_maximize_window(self):
if self.isMaximized():
self.showNormal()
self.ui.restore_window_button.setIcon(QtGui.QIcon(u":/icons/icons/maximize-2.svg"))
else:
self.showMaximized()
self.ui.restore_window_button.setIcon(QtGui.QIcon(u":/icons/icons/minimize-2.svg"))
def mousePressEvent(self, event):
self.clickPosition = event.globalPos()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

PYQT5: Window crashes trying to dynamically create image labels

Apologies if the question is confusing, I'm not the best at wording stuff. I'll try to explain further if required.
Background: I'm creating a simple image viewer that gives the user the ability to cycle through their library of images. I wanted to give the user the ability to browse through their image library (basically a file browser) so I tried creating a little browser that dynamically added QLabels with pixmap for each image in the library.
Problem: First my window crashed without loading any image labels, but since my image library is pretty huge I thought limiting the number would help. The results weren't so different; with the limitation (of only 4 images) the image labels displayed but anytime I try to do anything in the window (resize the window, resize the dock) it crashes. What am I doing wrong here?
Code:
import sys
import os
import time
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtGui as qtg
from PyQt5 import QtCore as qtc
from PIL import ImageQt, Image
import memory_profiler
from DBManager import DBBrowser
class MainWindow(qtw.QMainWindow):
resize_constant = 10
def __init__(self):
self.root = r'Images'
self.control_modifier = False
self.resized = 0
super().__init__()
self.main_widget = qtw.QWidget()
self.main_widget.setLayout(qtw.QVBoxLayout())
self.main_widget.layout().setSpacing(0)
self.setCentralWidget(self.main_widget)
# self.setWindowFlag(qtc.Qt.FramelessWindowHint)
self.create_main_window()
self.viewer()
self.menubar()
self.main_widget.layout().addWidget(self.menu_widget)
self.main_widget.layout().addWidget(self.main_window)
self.main_widget.layout().setContentsMargins(0,0,0,0)
self.show()
def menubar(self):
self.menu_widget = qtw.QWidget()
self.menu_widget.setLayout(qtw.QHBoxLayout())
self.menu_widget.layout().setContentsMargins(0,0,0,0)
self.menu_widget.layout().setSpacing(0)
self.menu_widget.layout().setAlignment(qtc.Qt.AlignLeft)
import_btn = qtw.QPushButton('Import', clicked=self.import_database)
explorer_btn = qtw.QPushButton('Explorer', clicked=self.show_hide_explorer)
import_btn.setFixedWidth(70)
explorer_btn.setFixedWidth(70)
self.menu_widget.layout().addWidget(import_btn)
self.menu_widget.layout().addWidget(explorer_btn)
import_btn.setFocusPolicy(qtc.Qt.ClickFocus)
explorer_btn.setFocusPolicy(qtc.Qt.ClickFocus)
def create_main_window(self):
self.main_window = qtw.QMainWindow()
self.dock = Dock('Explorer')
self.explorer = Explorer()
self.dock.setWidget(self.explorer)
self.dock.setTitleBarWidget(qtw.QWidget())
self.main_window.setFocusPolicy(qtc.Qt.StrongFocus)
self.main_window.setFocus()
self.main_window.addDockWidget(qtc.Qt.LeftDockWidgetArea, self.dock)
def viewer(self):
self.image_handler()
self.image_label = qtw.QLabel(alignment=qtc.Qt.AlignCenter)
self.curr_img_name = self.images[0]
self.curr_img_org = Image.open(os.path.join(self.root, self.curr_img_name))
self.curr_img_qt = ImageQt.ImageQt(self.curr_img_org)
self.curr_img_pixmap = qtg.QPixmap.fromImage(self.curr_img_qt)
self.image_label.setPixmap(self.curr_img_pixmap)
self.image_scrollarea = ImageScrollArea(self)
self.main_window.setCentralWidget(self.image_scrollarea)
self.image_scrollarea.setWidget(self.image_label)
self.image_scrollarea.setWidgetResizable(True)
self.image_scrollarea.setVerticalScrollBarPolicy(qtc.Qt.ScrollBarAlwaysOff)
self.image_scrollarea.setHorizontalScrollBarPolicy(qtc.Qt.ScrollBarAlwaysOff)
self.image_scrollarea.setFocusPolicy(qtc.Qt.NoFocus)
def image_handler(self):
self.images = sorted([(int(image.split(os.extsep)[0]), image.split(os.extsep)[1]) for image in os.listdir(self.root)
if os.path.isfile(os.path.join(self.root, image)) and not image.endswith('.csv')])
self.images = ['.'.join((str(image[0]), image[1])) for image in self.images]
def resize_image(self):
self.curr_img = self.curr_img_org.copy()
self.curr_img_qt = ImageQt.ImageQt(self.curr_img)
self.curr_img_pixmap = qtg.QPixmap.fromImage(self.curr_img_qt)
if self.resized < 0:
self.curr_img.thumbnail((
int(self.curr_img_org.width - (abs(self.resized)/100 * self.curr_img_org.width))
, int(self.curr_img_org.height - (abs(self.resized)/100 * self.curr_img_org.height)))
, Image.BOX)
self.curr_img_qt = ImageQt.ImageQt(self.curr_img)
self.curr_img_pixmap = qtg.QPixmap.fromImage(self.curr_img_qt)
elif self.resized > 0:
self.curr_img = self.curr_img_org.copy()
self.curr_img = self.curr_img.resize((
int((abs(self.resized)/100 * self.curr_img_org.width) + self.curr_img_org.width)
, int((abs(self.resized)/100 * self.curr_img_org.height) + self.curr_img_org.height))
, Image.BOX)
self.curr_img_qt = ImageQt.ImageQt(self.curr_img)
self.curr_img_pixmap = qtg.QPixmap.fromImage(self.curr_img_qt)
def change_image(self, direction):
current_index = self.images.index(self.curr_img_name)
if direction == qtc.Qt.Key_Left:
if current_index == 0:
return
self.curr_img_name = self.images[current_index-1]
self.curr_img_org = Image.open(os.path.join(self.root, self.curr_img_name))
self.curr_img_qt = ImageQt.ImageQt(self.curr_img_org)
self.curr_img_pixmap = qtg.QPixmap.fromImage(self.curr_img_qt)
if self.resized != 0:
self.resize_image()
self.image_label.setPixmap(self.curr_img_pixmap)
self.image_scrollarea.scroll_value = 0
self.image_scrollarea.verticalScrollBar().setValue(self.image_scrollarea.scroll_value)
if direction == qtc.Qt.Key_Right:
if current_index == len(self.images)-1:
return
self.curr_img_name = self.images[current_index+1]
self.curr_img_org = Image.open(os.path.join(self.root, self.curr_img_name))
self.curr_img_qt = ImageQt.ImageQt(self.curr_img_org)
self.curr_img_pixmap = qtg.QPixmap.fromImage(self.curr_img_qt)
if self.resized != 0:
self.resize_image()
self.image_label.setPixmap(self.curr_img_pixmap)
self.image_scrollarea.scroll_value = 0
self.image_scrollarea.verticalScrollBar().setValue(self.image_scrollarea.scroll_value)
def import_database(self):
file_location = qtw.QFileDialog.getOpenFileName(self, 'Import database', os.path.abspath('.'), 'database files (*.db)')
self.explorer.set_database_location(file_location[0])
self.explorer.offset = 0
gallery_data_dict_list = self.explorer.get_items()
self.explorer.set_items(gallery_data_dict_list)
def show_hide_explorer(self):
if self.dock.isVisible():
self.dock.hide()
else:
self.dock.show()
def keyPressEvent(self, event):
if event.key() == qtc.Qt.Key_Left:
self.change_image(qtc.Qt.Key_Left)
if event.key() == qtc.Qt.Key_Right:
self.change_image(qtc.Qt.Key_Right)
if event.key() == qtc.Qt.Key_Up:
self.image_scrollarea.scroll_(120)
if event.key() == qtc.Qt.Key_Down:
self.image_scrollarea.scroll_(-120)
if event.key() == qtc.Qt.Key_Escape:
if self.dock.isVisible():
self.dock.hide()
if event.key() == qtc.Qt.Key_Control:
self.control_modifier = True
if self.control_modifier:
if event.key() == qtc.Qt.Key_E:
self.show_hide_explorer()
def keyReleaseEvent(self, event):
if event.key() == qtc.Qt.Key_Control:
self.control_modifier = False
def wheelEvent(self, event):
if self.control_modifier:
if event.angleDelta().y() == 120:
self.resized += 10
if self.resized >= 90: self.resized = 90
self.resize_image()
self.image_label.setPixmap(self.curr_img_pixmap)
elif event.angleDelta().y() == -120:
self.resized -= 10
if self.resized <= -90: self.resized = -90
self.resize_image()
self.image_label.setPixmap(self.curr_img_pixmap)
class ImageScrollArea(qtw.QScrollArea):
def __init__(self, main_window):
super().__init__()
self.main_window = main_window
self.scroll_value = self.verticalScrollBar().minimum()
self.scroll_constant = 100
def wheelEvent(self, event):
if self.main_window.control_modifier:
event.ignore()
else:
self.scroll_(event.angleDelta().y())
def scroll_(self, y):
if y == -120:
if self.scroll_value + self.scroll_constant >= self.verticalScrollBar().maximum():
self.scroll_value = self.verticalScrollBar().maximum()
else:
self.scroll_value += self.scroll_constant
elif y == 120:
if self.scroll_value - self.scroll_constant <= self.verticalScrollBar().minimum():
self.scroll_value = self.verticalScrollBar().minimum()
else:
self.scroll_value -= self.scroll_constant
self.verticalScrollBar().setValue(self.scroll_value)
class Dock(qtw.QDockWidget):
def __init__(self, title):
super().__init__()
self.setWindowTitle(title)
class Explorer(qtw.QWidget):
def __init__(self):
super().__init__()
# self.database_location = None
self.setLayout(qtw.QVBoxLayout())
self.search_box = qtw.QWidget()
self.search_box.setFixedHeight(int(0.15*self.height()))
self.search_box.setLayout(qtw.QFormLayout())
self.layout().addWidget(self.search_box)
search_edit = qtw.QLineEdit()
search_edit.setPlaceholderText('Enter search term(s)...')
search_bar = qtw.QHBoxLayout()
filter_options = ['tags', 'people', 'date', 'custom...']
filter_option_combobox = qtw.QComboBox()
filter_option_combobox.addItems(filter_options)
filter_option_combobox.setCurrentIndex(0)
filter_option_combobox.currentTextChanged.connect(self.custom_filters)
search_btn = qtw.QPushButton('Search')
search_bar.addWidget(filter_option_combobox)
search_bar.addWidget(search_btn)
self.search_box.layout().addRow(search_edit)
self.search_box.layout().addRow(search_bar)
self.browser()
self.layout().addWidget(self.browser_scrollarea)
def custom_filters(self, value):
if value == 'custom...':
pass
def browser(self):
self.browser_scrollarea = qtw.QScrollArea()
self.browser_scrollarea.setVerticalScrollBarPolicy(qtc.Qt.ScrollBarAlwaysOn)
self.browser_scrollarea.setHorizontalScrollBarPolicy(qtc.Qt.ScrollBarAlwaysOn)
def get_items(self):
self.DBB = DBBrowser()
self.DBB.set_database(database_location=self.database_location)
self.DBB.set_filters()
results = self.DBB.sqlite_select(get='*', order_by='date', order_in='ASC', table='Library')
self.offset += 10
gallery_data_dict_list = [{
'location' : result[0],
'date' : result[1],
'tags' : result[2]
} for result in results]
return gallery_data_dict_list
def set_items(self, gallery_data_dict_list):
self.browser_widget = qtw.QWidget()
self.browser_widget.setLayout(qtw.QGridLayout())
key = 0
for gallery_data_dict in gallery_data_dict_list:
if key > 3:
break
description = qtw.QScrollArea()
text = qtw.QLabel('texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttex')
description.setWidget(text)
thumbnail = Image.open(os.path.join(gallery_data_dict['location'], os.listdir(gallery_data_dict['location'])[0]))
thumbnail.thumbnail((250,250))
thumbnail = ImageQt.ImageQt(thumbnail)
self.thumbnail_pixmap = qtg.QPixmap.fromImage(self.thumbnail)
self.thumb = qtw.QLabel(pixmap=self.thumbnail_pixmap)
# text.setFixedWidth(int(self.browser_scrollarea.width()*50/100))
self.browser_widget.layout().addWidget(self.thumb, key, 0)
self.browser_widget.layout().addWidget(description, key, 1)
key += 1
self.browser_scrollarea.setWidget(self.browser_widget)
def set_database_location(self, location):
self.database_location = location
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
mw = MainWindow()
sys.exit(app.exec_())
Edit:
Following #musicamante's comment, I tried a couple of things to reprex my question and it doesn't seem like anything but a random occurrence with a 99.999% fail rate. I don't say 100% because the same code that crashed a million times worked fine once. I tried stripping the code to nothing but just a QWidget with two widgets; a button to load the browser, and the browser. Nevertheless, it still crashed. I don't know how much more minimal I can go.
Then I realized, I was using PIL.Image and PIL.ImageQt instead of QPixmap. Changing all my images to use qt's pixmap instead fixed the problem, as far as my experience went. I tried using PIL.Image for the main viewer and QPixmap for the browser but it still crashed.
My question now is, is there a way I can make it work well with PIL? Because, unless I'm missing something, I feel like PIL.Image is a lot more feature rich for image manipulation than QPixmap. Namely resizing the image (PIL has a ton of algorithms but QPixmap only has Qt.FastTransformation and Qt.SmoothTransformation as far as I'm aware) and especially the .copy() function. Or alternatively, is there some other library?

In python, how can I get a value from a Gtk.entry entry box and pass it to a variable?

I've been struggling for a two days now to get the user input from entry3, entry2, and entry 1 and define 3 variables l, w, and h with it. No matter what I try I cannot get Gtk.Entry.get_text() to recognize my entrys! Here is my code; it launches a nice little gui I created for solving Pythagorean theorem problems.
#!usr/bin/env python
import math
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
a = False
b = False
c = True #changed for test
l = 0
w = 0
h = 0
ans = 0
class MyGI(Gtk.Window):
def gtk_main_quit(self, *args):
Gtk.main_quit(*args)
raise SystemExit
def solve(self, widget):
self.builder = Gtk.Builder()
l = self.builder.get_object('entry3')
float(l)
print l
if a == True:
ans = math.pow(h, 2) - math.pow(w, 2)
ans = math.sqrt(ans)
print(ans)
if b == True:
ans = math.pow(h, 2) - math.pow(l, 2)
ans = math.sqrt(ans)
print(ans)
if c == True:
ans = math.pow(l, 2) + math.pow(w, 2)
ans = math.sqrt(ans)
print(ans)
def a_x(self, widget):
a = True
b = False
c = False
print a
def b_x(self, widget):
a = False
b = True
c = False
def c_x(self, widget):
a = False
b = False
c = True
def entree(self, widget):
pass
builder = Gtk.Builder()
builder.add_from_file("pythag.glade")
builder.connect_signals(MyGI())
window = builder.get_object("window1") #old window method
window.show_all()
Gtk.main()
Any help is appreciated, I am at the end of my rope. This is the only problem left to solve
You aren't supposed to use GtkBuilder like that. You're supposed to use it once per .ui file, when you create your window (so, for example, in the __init__ of your class), and then get_object() everything into instance variables.
My Python is rusty, so, something like this:
def __init__(self):
super().__init__()
builder = Gtk.Builder.new_from_file("pythag.glade")
builder.connect_signals(self)
self.window = builder.get_object("window1")
self.entry3 = builder.get_object("entry3")
self.window.show_all()
def solve(self, widget):
float(self.entry3)
To get the text from a GtkEntry, use the syntax entryObject.props.text.

qt stackwidget animation; previous widget disappears

I am trying to use the animation tools (QPropertyAnimation) in Qt to animate the changing of a QStackedWidget. Unfortunately, there are two issues:
The previous widget disappears (doesn't animate)
The next widget does not change position until visible
Any ideas?
Python 2.7, PyQt4, Win 7, Win 10, OpenSuse
Complete Example
import sys
from PyQt4 import QtCore, QtGui
COLOR_LIST = ['red','blue','green']
ANIMATION_SPEED = 2000
def make_callback(func, *param):
'''
Helper function to make sure lambda functions are cached and not lost.
'''
return lambda: func(*param)
class App(QtGui.QMainWindow):
def __init__(self, app, parent=None):
QtGui.QMainWindow.__init__(self, parent)
# reference to qapp instance
self.app = app
self.animating = False
self.stack_animation = None
self.resize(QtCore.QSize(500,200))
# widgets
self.mainwidget = QtGui.QWidget()
self.setCentralWidget(self.mainwidget)
self.listwidget = QtGui.QListWidget()
self.listwidget.addItems(COLOR_LIST)
self.listwidget.itemSelectionChanged.connect(self.change_color)
self.stackedwidget = QtGui.QStackedWidget()
for color in COLOR_LIST:
widget = QtGui.QWidget()
widget.setStyleSheet('QWidget{'
' background-color: '+color+';'
'}')
widget.setObjectName(color)
self.stackedwidget.addWidget(widget)
# layouts
self.hlayout = QtGui.QHBoxLayout(self.mainwidget)
self.mainwidget.setLayout(self.hlayout)
self.hlayout.addWidget(self.listwidget)
self.hlayout.addWidget(self.stackedwidget)
def change_color(self):
new_color = str(self.listwidget.currentItem().text())
old_color = str(self.stackedwidget.currentWidget().objectName())
old_index = self.stackedwidget.currentIndex()
new_index = 0
for i in range(self.stackedwidget.count()):
widget = self.stackedwidget.widget(i)
if new_color == str(widget.objectName()):
new_index = i
break
print('Changing from:', old_color, old_index,
'To:', new_color, new_index)
self.animate(old_index, new_index)
def animate(self, from_, to, direction='vertical'):
""" animate changing of qstackedwidget """
# check to see if already animating
if self.animating and self.stack_animation is not None:
self.stack_animation.stop()
from_widget = self.stackedwidget.widget(from_)
to_widget = self.stackedwidget.widget(to)
# get from geometry
width = from_widget.frameGeometry().width()
height = from_widget.frameGeometry().height()
# offset
# bottom to top
if direction == 'vertical' and from_ < to:
offsetx = 0
offsety = height
# top to bottom
elif direction == 'vertical' and from_ > to:
offsetx = 0
offsety = -height
elif direction == 'horizontal' and from_ < to:
offsetx = width
offsety = 0
elif direction == 'horizontal' and from_ > to:
offsetx = -width
offsety = 0
else:
return
# move to widget and show
# set the geometry of the next widget
to_widget.setGeometry(0 + offsetx, 0 + offsety, width, height)
to_widget.show()
to_widget.lower()
to_widget.raise_()
# animate
# from widget
animnow = QtCore.QPropertyAnimation(from_widget, "pos")
animnow.setDuration(ANIMATION_SPEED)
animnow.setEasingCurve(QtCore.QEasingCurve.InOutQuint)
animnow.setStartValue(
QtCore.QPoint(0,
0))
animnow.setEndValue(
QtCore.QPoint(0 - offsetx,
0 - offsety))
# to widget
animnext = QtCore.QPropertyAnimation(to_widget, "pos")
animnext.setDuration(ANIMATION_SPEED)
animnext.setEasingCurve(QtCore.QEasingCurve.InOutQuint)
animnext.setStartValue(
QtCore.QPoint(0 + offsetx,
0 + offsety))
animnext.setEndValue(
QtCore.QPoint(0,
0))
# animation group
self.stack_animation = QtCore.QParallelAnimationGroup()
self.stack_animation.addAnimation(animnow)
self.stack_animation.addAnimation(animnext)
self.stack_animation.finished.connect(
make_callback(self.animate_stacked_widget_finished,
from_, to)
)
self.stack_animation.stateChanged.connect(
make_callback(self.animate_stacked_widget_finished,
from_, to)
)
self.animating = True
self.stack_animation.start()
def animate_stacked_widget_finished(self, from_, to):
""" cleanup after animation """
self.stackedwidget.setCurrentIndex(to)
from_widget = self.stackedwidget.widget(from_)
from_widget.hide()
from_widget.move(0, 0)
self.animating = False
if __name__ == '__main__':
qapp = QtGui.QApplication(sys.argv)
app = App(qapp)
app.show()
qapp.exec_()
qapp.deleteLater()
sys.exit()
The QtCore.QParallelAnimationGroup.stateChanged signal is called when the animation starts, so it was calling my animate_stacked_widget_finished method and hiding the from_widget.
Still need to catch this event to handle when the animation is finished. Just need to add an if statement to check the state of the QParallelAnimationGroup.
Replace the animate_stacked_widget_finished with:
def animate_stacked_widget_finished(self, from_, to):
""" cleanup after animation """
if self.stack_animation.state() == QtCore.QAbstractAnimation.Stopped:
self.stackedwidget.setCurrentIndex(to)
from_widget = self.stackedwidget.widget(from_)
from_widget.hide()
from_widget.move(0, 0)
self.animating = False

Pyqt Embedding Graphics object in Widget

So I have a main window. I use setCentralWidget to set it to a class I made called mainWindowWidget to handle the UI.
I am now trying to add a graphics view widget I made to that but cannot seem to get anything to display. If I set the graphics view as the central widget I can see it and all my behaviour is working.
Do I need to do anything to get the graphics view to display within another widget?
Below are the sections of code I think are relevant to the question followed by the entire application. I am really new to PyQt and any guidance would be appreciated.
class mainWindowWidget(QtGui.QWidget):
grid = None
scene = None
def __init__(self):
self.initScene()
QtGui.QWidget.__init__(self)
def initScene(self):
self.grid = QtGui.QGridLayout()
'''Node Interface'''
self.scene = Scene(0, 0, 1280, 720, self)
self.view = QtGui.QGraphicsView()
self.view.setScene(self.scene)
self.grid.addWidget(self.view)
'''AttributeWindow'''
class MainWindowUi(QtGui.QMainWindow):
def __init__(self):
mainDataGraber = ind.dataGraber()
QtGui.QMainWindow.__init__(self)
self.setWindowTitle('RIS RIB Generator')
mainwindowwidget = mainWindowWidget()
self.setCentralWidget(mainwindowwidget)
This is the main GUI file for the application
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
This is the base py file for the GUI
Todo list
-----------------
- Pop up menu for adding new Nodes
- node connectivity
- create data structure for storing
"""
#import code mods
import sys
import uuid
import gtk, pygtk
from PyQt4 import QtGui, QtCore
from array import *
#import StyleMod
import RRG_NodeInterfaceGUIStyle as ns
import RRG_importNodeData as ind
"""
Base class for a node. Contains all the inilization, drawing, and containing inputs and outputs
"""
class node(QtGui.QGraphicsRectItem):
nid = 0
width = ns.nodeWidth
height = ns.nodeHeight
color = ns.nodeBackgroundColor
alpha = ns.nodeBackgroundAlpha
x = 90
y = 60
inputs=[]
outputs=[]
viewObj = None
isNode = True
scene = None
def __init__(self, n_x, n_y, n_width,n_height, n_scene):
QtGui.QGraphicsRectItem.__init__(self, n_x, n_y, n_width, n_height)
self.width = n_width
self.height = n_height
self.x = n_x
self.y = n_y
self.scene = n_scene
self.nid = uuid.uuid4()
print(self.nid)
self.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
self.iniNodeData()
def mousePressEvent(self, e):
print("Square got mouse press event")
print("Event came to us accepted: %s"%(e.isAccepted(),))
a = []
self.scene.selectedNodes = a
self.scene.selectedNodes.append(self)
self.scene.selectedNodeID = self.nid
QtGui.QGraphicsRectItem.mousePressEvent(self, e)
def mouseReleaseEvent(self, e):
#print("Square got mouse release event")
#print("Event came to us accepted: %s"%(e.isAccepted(),))
QtGui.QGraphicsRectItem.mouseReleaseEvent(self, e)
"""
This is where inputs and outputs will be created based on node type
"""
def iniNodeData(self):
print('making node data')
for j in range(5):
this = self
x = input(this,0, 0+(j*10),self.scene)
self.inputs.append(x)
for k in range(5):
this = self
x = output(this, self.width-10, 0+(k*10),self.scene)
self.outputs.append(x)
def mouseMoveEvent(self, event):
self.scene.updateConnections()
QtGui.QGraphicsRectItem.mouseMoveEvent(self, event)
def nid(self):
return self.nid
"""
Nodes will evaluate from the last node to the first node, therefore inputs are evaluted
"""
class input(QtGui.QGraphicsRectItem):
currentConnectedNode = None
currentConnectedOutput = None
parentNode = None
width = 10
height = 10
x = 1
y = 1
color = 1
drawItem = None
isOutput = False
isNode = False
scene = None
points = []
line = None
def __init__(self, pnode, posX, posY, n_scene):
self.parentNode = pnode
self.x = posX
self.y = posY
self.color = 1
self.scene = n_scene
QtGui.QGraphicsRectItem.__init__(self, self.x+self.parentNode.x, self.y+self.parentNode.y, self.width, self.height, self.parentNode)
self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
'''
This will handel connections. It determins if a connection is allowed aswell as creates them
'''
def mousePressEvent(self, e):
#print("Square got mouse press event")
#print("Event came to us accepted: %s"%(e.isAccepted(),))
emptyArray = []
if len(self.scene.selectedNodes) > 0 or len(self.scene.selectedNodes) > 1:
a = self.scene.selectedNodes[0]
if a.isNode == False:
if a.parentNode != self.parentNode:
if a.isOutput == True and self.isOutput == False:
print('Output and Input! line test runnin....')
currentConnectedOutput = a
currentConnectedNode = a.parentNode
if self.line != None:
self.line = None
self.scene.addConnection(self, a)
elif a.isOutput == True and self.isOutput == True:
print('Output and Output')
elif a.isOutput == False and self.isOutput == False:
print('Input and Input')
self.scene.selectedNodes = emptyArray
else:
self.scene.selectedNodes = emptyArray
else:
self.scene.selectedNodes = emptyArray
self.scene.selectedNodes.append(self)
else:
self.scene.selectedNodes.append(self)
QtGui.QGraphicsRectItem.mousePressEvent(self, e)
'''
Output value from a node
'''
class output(QtGui.QGraphicsRectItem):
parentNode = None
width = 10
height = 10
x = 0
y = 0
isOutput = True
isNode = False
scene = None
def __init__(self, pnode, posX, posY, n_scene):
self.parentNode = pnode
self.x = posX
self.y = posY
self.color = 1
self.scene = n_scene
QtGui.QGraphicsRectItem.__init__(self, self.x+self.parentNode.x, self.y+self.parentNode.y, self.width, self.height, self.parentNode)
self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
'''
This will handel connections. It determins if a connection is allowed aswell as creates them
'''
def mousePressEvent(self, e):
#print("Square got mouse press event")
#print("Event came to us accepted: %s"%(e.isAccepted(),))
emptyArray = []
if len(self.scene.selectedNodes) > 0 or len(self.scene.selectedNodes) > 1:
a = self.scene.selectedNodes[0]
if a.isNode == False:
if a.parentNode != self.parentNode:
if a.isOutput == False and self.isOutput == True:
print('Input and Output!')
a.currentConnectedOutput = self
a.currentConnectedNode = self.parentNode
elif a.isOutput == True and self.isOutput == False:
print('Output and Input!')
elif a.isOutput == True and self.isOutput == True:
print('Output and Output')
elif a.isOutput == False and self.isOutput == False:
print('Input and Input')
self.scene.selectedNodes = emptyArray
else:
self.scene.selectedNodes = emptyArray
else:
self.scene.selectedNodes = emptyArray
self.scene.selectedNodes.append(self)
else:
self.scene.selectedNodes.append(self)
QtGui.QGraphicsRectItem.mousePressEvent(self, e)
class connection(QtGui.QGraphicsLineItem):
usedNodeIDs = []
inputItem = None
outputItem = None
x1 = 0.0
y1 = 0.0
x2 = 0.0
y2 = 0.0
nid = None
scene = None
def __init__(self, n_inputItem, n_outputItemm, n_scene):
self.inputItem = n_inputItem
self.outputItem = n_outputItemm
self.usedNodeIDs.append(self.inputItem.parentNode.nid)
self.usedNodeIDs.append(self.outputItem.parentNode.nid)
self.updatePos()
QtGui.QGraphicsLineItem.__init__(self, self.x1, self.y1, self.x2, self.y2)
self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
self.scene = n_scene
self.nid = uuid.uuid4()
def update(self):
self.updatePos()
self.setLine(self.x1, self.y1, self.x2, self.y2)
def updatePos(self):
scenePosInput = QtGui.QGraphicsItem.pos(self.inputItem)
scenePosOutput = QtGui.QGraphicsItem.pos(self.outputItem)
scenePosInputNode = QtGui.QGraphicsItem.pos(self.inputItem.parentNode)
scenePosOutputNode = QtGui.QGraphicsItem.pos(self.outputItem.parentNode)
self.x1 = (scenePosInputNode.x()+self.inputItem.parentNode.x)+(scenePosInput.x()+self.inputItem.x) + ns.inputWidth/2
self.y1 = (scenePosInputNode.y()+self.inputItem.parentNode.y)+(scenePosInput.y()+self.inputItem.y) + ns.inputHeight/2
self.x2 = (scenePosOutputNode.x()+self.outputItem.parentNode.x)+(scenePosOutput.x()+self.outputItem.x) + ns.outputWidth/2
self.y2 = (scenePosOutputNode.y()+self.outputItem.parentNode.y)+(scenePosOutput.y()+self.outputItem.y) + ns.outputHeight/2
def mousePressEvent(self, e):
self.scene.selectedNodeID = self.nid
QtGui.QGraphicsLineItem.mousePressEvent(self, e)
'''
Check Click events on the scene Object
Also Stores the node data
'''
class Scene(QtGui.QGraphicsScene):
nodes = []
connections = []
selectedNodeID = None
def __init__(self, x, y, w, h, p):
super(Scene, self).__init__()
self.width = w
self.height = h
def mousePressEvent(self, e):
#print("Scene got mouse press event")
#print("Event came to us accepted: %s"%(e.isAccepted(),))
QtGui.QGraphicsScene.mousePressEvent(self, e)
def mouseReleaseEvent(self, e):
#print("Scene got mouse release event")
#print("Event came to us accepted: %s"%(e.isAccepted(),))
QtGui.QGraphicsScene.mouseReleaseEvent(self, e)
def dragMoveEvent(self, e):
QtGui.QGraphicsScene.dragMoveEvent(self, e)
def updateConnections(self):
for connect in self.connections:
connect.update()
def addNode(self):
newNode = node(250,250,100,150, self)
self.addItem(newNode)
self.nodes.append(newNode)
def addPatternNode(self):
newNode = node(250,250,100,150, self)
self.addItem(newNode)
self.nodes.append(newNode)
def addConnection(self, n_inputItem, n_outputItem):
newConnection = connection(n_inputItem, n_outputItem, self)
self.addItem(newConnection)
self.connections.append(newConnection)
def keyPressEvent(self, e):
#Delete a node after it have been clicked on
#Use the node ID as the unique ID of the node to delete
if e.key() == QtCore.Qt.Key_Delete or e.key() == QtCore.Qt.Key_Backspace:
#If nothing selected
if self.selectedNodeID != None:
isConnection = False
for j in range(len(self.connections)):
if self.connections[j].nid == self.selectedNodeID:
isConnection = True
self.removeItem(self.connections[j])
self.connections.remove(self.connections[j])
if isConnection != True:
#first remove connections
rmItem = False
connectionsToRemove = []
for connect in self.connections:
rmItem = False
for nid in connect.usedNodeIDs:
if nid == self.selectedNodeID:
if rmItem == False:
connectionsToRemove.append(connect)
rmItem = True
for removeThis in connectionsToRemove:
self.connections.remove(removeThis)
self.removeItem(removeThis)
#now remove the nodes
for j in range(len(self.nodes)):
print(self.nodes[j].nid)
#figure out which node in our master node list must be deleted
if self.nodes[j].nid == self.selectedNodeID:
self.removeItem(self.nodes[j])
self.nodes.remove(self.nodes[j])
self.selectedNodeID = None
class mainWindowWidget(QtGui.QWidget):
grid = None
scene = None
def __init__(self):
self.initScene()
QtGui.QWidget.__init__(self)
def initScene(self):
self.grid = QtGui.QGridLayout()
'''Node Interface'''
self.scene = Scene(0, 0, 1280, 720, self)
self.view = QtGui.QGraphicsView()
self.view.setScene(self.scene)
self.grid.addWidget(self.view)
'''AttributeWindow'''
class MainWindowUi(QtGui.QMainWindow):
def __init__(self):
mainDataGraber = ind.dataGraber()
QtGui.QMainWindow.__init__(self)
self.setWindowTitle('RIS RIB Generator')
mainwindowwidget = mainWindowWidget()
self.setCentralWidget(mainwindowwidget)
exitAction = QtGui.QAction(QtGui.QIcon('exit24.png'), 'Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip('Exit application')
exitAction.triggered.connect(self.close)
newNodeAction = QtGui.QAction(QtGui.QIcon('exit24.png'), 'New Node', self)
newNodeAction.setStatusTip('Add a blank node')
newNodeAction.triggered.connect(mainwindowwidget.scene.addPatternNode)
nodeCreationActions = []
for nodeType in mainDataGraber.abstractNodeObjects:
nodeName = nodeType.nName
nodeType = nodeType.nType
#nodeStatusTip = nodeType.nhelp
newNodeAction = QtGui.QAction(QtGui.QIcon('exit24.png'), nodeName, self)
newNodeAction.setStatusTip('nodeType.nhelp')
if nodeType == 'pattern':
newNodeAction.triggered.connect(mainwindowwidget.scene.addPatternNode)
nodeCreationActions.append(newNodeAction)
newNodeAction = QtGui.QAction(QtGui.QIcon('exit24.png'), 'New Node', self)
newNodeAction.setStatusTip('Add a blank node')
newNodeAction.triggered.connect(mainwindowwidget.scene.addPatternNode)
self.statusBar()
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(newNodeAction)
nodeMenu = menubar.addMenu('&Nodes')
for action in nodeCreationActions:
nodeMenu.addAction(action)
fileMenu.addAction(exitAction)
'''
Start Point
'''
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
win = MainWindowUi()
win.show()
sys.exit(app.exec_())
Your issue is that you don't specify a parent for the QGridLayout (in the mainWindowWidget class), so it isn't attached to a widget. This results in the layout (and all widgets contained within it) not being visible. Adding a parent to the layout reveals a second problem in that you try and do things with the QWidget before calling __init__.
The corrected code is thus:
class mainWindowWidget(QtGui.QWidget):
grid = None
scene = None
def __init__(self):
QtGui.QWidget.__init__(self)
self.initScene()
def initScene(self):
self.grid = QtGui.QGridLayout(self)
'''Node Interface'''
self.scene = Scene(0, 0, 1280, 720, self)
self.view = QtGui.QGraphicsView()
self.view.setScene(self.scene)
self.grid.addWidget(self.view)
Note: For future questions requiring debugging help, please make a minimilistic example that is runnable. Don't just dump 90% of your code in a stack overflow post. It's not fun trying to dig through random code trying to cut out the missing imports so that it still reproduces the problem (fortunately it wasn't too difficult in this case). See How to create a Minimal, Complete, and Verifiable example.
Note 2: Why are you importing pygtk into a qt app?

Categories