How to make a Grid in wxPython? - python

I want to make a grid like this:
Not the wx.Grid. Does anyone know how to do this, and could provide an example?
This would be for a GridSizer or GridBagSizer to separate the widgets.

use the drawing context of the frame wxWindow subclass(frame/panel/etc...really any wxObject almost).
one way of doing it is this
import wx
class MyCustomFrame(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id)
self.Bind(wx.EVT_PAINT,self.OnPaint)
def OnPaint(self,evt):
self.dc = dc = wx.PaintDC(self)
p1 = [0,0]
p2 = [500,0]
for i in range(100):
dc.DrawLine(p1[0],p1[1],p2[0],p2[1])
p1 = [p1[0],p1[1]+5]
p2 = [p2[0],p2[1]+5]
p1=[0,0]
p2 = [0,500]
for i in range(100):
dc.DrawLine(p1[0],p1[1],p2[0],p2[1])
p1 = [p1[0]+5,p1[1]]
p2 = [p2[0]+5,p2[1]]
if __name__ == "__main__":
a = wx.App(redirect=False)
f = MyCustomFrame(None,-1)
#f.OnPaint(None) --- dont do this!!!
f.Show()
a.MainLDop()
you could speed it up by using drawlines instead
def OnPaint(self,evt):
self.dc = dc = wx.PaintDC(self)
verticle_lines = [(i*5,0,i*5,500) for i in range(100)]
horizontal_lines = [(0,i*5,500,i*5) for i in range(100)]
dc.DrawLineList(horizontal_lines+verticle_lines)
In Order to do what you want with the grid sizer you could do this
import wx
class MyCustomPanel(wx.Panel):
def __init__(self,parent,id):
wx.Panel.__init__(self,parent,id)
self.sz = wx.GridSizer(5,5,0,0)
for i in range(25):
self.sz.Add(wx.StaticText(self,-1,str(i)))
self.SetSizer(self.sz)
self.Bind(wx.EVT_PAINT,self.OnPaint)
def OnPaint(self,evt):
self.dc = dc = wx.PaintDC(self)
w,h = self.sz.GetSize()
nr = self.sz.GetRows()
nc = self.sz.GetCols()
cell_w = float(w)/nc
cell_h = float(h)/nr
hlines = [(0,i*cell_h,w,i*cell_h)for i in range(nr+1)]
vlines = [(i*cell_w,0,i*cell_w,h)for i in range(nc+1)]
self.dc.DrawLineList(hlines+vlines)
if __name__ == "__main__":
a = wx.App(redirect=False)
f1 = wx.Frame(None,-1)
f = MyCustomPanel(f1,-1)
#f.OnPaint(None)
f1.Show()
a.MainLoop()
you could also accomplish this with styles like this
import wx
class SimplePanel(wx.Panel):
def __init__(self,parent,id,str_val):
wx.Panel.__init__(self,parent,id,style=wx.SIMPLE_BORDER)
self.sz = wx.BoxSizer()
self.sz.Add(wx.StaticText(self,-1,str_val),0,wx.ALIGN_CENTER)
self.SetSizer(self.sz)
class MyCustomPanel(wx.Panel):
def __init__(self,parent,id):
wx.Panel.__init__(self,parent,id)
self.sz = wx.GridSizer(5,5,0,0)
for i in range(25):
self.sz.Add(SimplePanel(self,-1,str(i)),0,wx.GROW)
self.SetSizer(self.sz)
if __name__ == "__main__":
a = wx.App(redirect=False)
f1 = wx.Frame(None,-1)
f = MyCustomPanel(f1,-1)
#f.OnPaint(None)
f1.Show()
a.MainLoop()

Related

Pyside/Pyqt5 dynamically adding and sorting items

I have a simple user interface where I want to dynamically add frames and labels in a widget (as I will use these labels to transmit a video feed from my webcams).
In the following code I set a function where the user selects an integer which represents the number of labels(webcams) they want to see and then dynamically adds these labels& frames to the widget:
def loopCamFeed(self,n):
if (n % 2) == 0:
dividnd = n / 2
for i in range(2):
self.frame_12 = QFrame(self.ui.webcamWidget)
self.frame_12.setObjectName(u"frame_12")
self.frame_12.setFrameShape(QFrame.StyledPanel)
self.frame_12.setFrameShadow(QFrame.Raised)
self.horizontalLayout_14 = QHBoxLayout(self.frame_12)
self.horizontalLayout_14.setObjectName(u"horizontalLayout_14")
for i in range(int(dividnd)):
self.label_5 = QLabel("hello",self.frame_12)
self.label_5.setObjectName(u"label_5")
self.horizontalLayout_14.addWidget(self.label_5, 0, Qt.AlignHCenter)
self.ui.verticalLayout_15.addWidget(self.frame_12)
Which displays the labels as in the image below:
--By adding a value of 2:
--By adding a value of 4):
By adding a value of 8:
The challenge that I am facing is how to handle an odd number selection. For example, if a user selects 3 or 7 webcams/labels.
If a user selects 3 labels/webcams, I'd want to show one on the top frame and two at the bottom.
MAIN.PY (Where this piece of code was written):
from ui_interface import *
import sys
from Custom_Widgets.Widgets import *
import cv2
import numpy as np
from PyQt5.QtCore import pyqtSignal, QObject, QThread
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
loadJsonStyle(self, self.ui)
self.show()
#Expand Center Menu Widget
self.ui.settingsBtn.clicked.connect(lambda: self.ui.centerMenuContainer.expandMenu())
self.ui.infoBtn.clicked.connect(lambda: self.ui.centerMenuContainer.expandMenu())
self.ui.helpBtn.clicked.connect(lambda: self.ui.centerMenuContainer.expandMenu())
#Close Center Menu Widget
self.ui.closeCenterMenuButton.clicked.connect(lambda: self.ui.centerMenuContainer.collapseMenu())
#Close Notification Menu Widget
self.ui.closeNotificationBtn.clicked.connect(lambda: self.ui.popUpNotificationContainer.collapseMenu())
self.loopCamFeed(4)
def ImageUpdateSlot(self, Image):
self.ui.label_5.setPixmap(QPixmap.fromImage(Image))
def CancelFeed(self):
self.worker1.stop()
def startVideo(self):
self.worker1 = Worker1()
self.worker1.start()
self.worker1.ImageUpdate.connect(self.ImageUpdateSlot)
def loopCamFeed(self,n):
if (n % 2) == 0:
dividnd = n / 2
for i in range(2):
self.frame_12 = QFrame(self.ui.webcamWidget)
self.frame_12.setObjectName(u"frame_12")
self.frame_12.setFrameShape(QFrame.StyledPanel)
self.frame_12.setFrameShadow(QFrame.Raised)
self.horizontalLayout_14 = QHBoxLayout(self.frame_12)
self.horizontalLayout_14.setObjectName(u"horizontalLayout_14")
for i in range(int(dividnd)):
self.label_5 = QLabel("hello",self.frame_12)
self.label_5.setObjectName(u"label_5")
self.horizontalLayout_14.addWidget(self.label_5, 0, Qt.AlignHCenter)
self.ui.verticalLayout_15.addWidget(self.frame_12)
class Worker1(QThread):
ImageUpdate = pyqtSignal(QImage)
def __init__(self):
super().__init__()
def run(self):
self.ThreadActive = True
Capture = cv2.VideoCapture(0)
while self.ThreadActive:
ret, frame = Capture.read()
if ret:
Image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
FlippedImage = cv2.flip(Image, 1)
ConvertToQtFormat = QImage(FlippedImage.data, FlippedImage.shape[1], FlippedImage.shape[0], QImage.Format_RGB888)
Pic = ConvertToQtFormat.scaled(1200, 900, Qt.KeepAspectRatio)
self.ImageUpdate.emit(Pic)
def stop(self):
self.ThreadActive = False
self.quit()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Use a grid layout instead of a horizontal layout:
def loopCamFeed(self,n):
self.frame_12 = QFrame(self.ui.webcamWidget)
self.frame_12.setObjectName(u"frame_12")
self.frame_12.setFrameShape(QFrame.StyledPanel)
self.frame_12.setFrameShadow(QFrame.Raised)
self.grid_layout = QGridLayout(self.frame_12)
self.grid_layout.setObjectName(u"grid_layout")
for i in range(int(n)):
self.label_5 = QLabel("hello",self.frame_12)
self.label_5.setObjectName(u"label_5")
self.grid_layout.addWidget(self.label_5, 0, Qt.AlignHCenter)
self.ui.verticalLayout_15.addWidget(self.frame_12)
As Medhat mentioned, applying the GridLayout was the best solution.
I applied the following code:
def loopCamFeed(self,n):
w = 0
if n > 0:
# if ( n % 2) == 0:
for i in range(int(n)):
if (i%2) == 0:
w +=1
print(int(w / 2), (i%2))
self.label = QtWidgets.QLabel()
self.label.setText("Screen " +str(i))
self.label.setStyleSheet("background-color: black5;")
self.label.setObjectName(u"label")
self.gridLayout.addWidget(self.label, (i%2) ,int(w),Qt.AlignHCenter )
This works perfectly! Thanks #Medhat

How make application desktop toolbar UI with PyQT5

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_())

How to create a grid of splitters

What I'm trying to do is add splitter to a QGridLayout in order to resize the layout with the mouse. So for instance with this :
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
super(SurfViewer, self).__init__()
self.parent = parent
self.setFixedWidth(300)
self.setFixedHeight(100)
self.wid = QWidget()
self.setCentralWidget(self.wid)
self.grid = QGridLayout()
l_a = QLabel('A')
l_b = QLabel('B')
l_c = QLabel('C')
l_d = QLabel('D')
l_e = QLabel('E')
l_f = QLabel('F')
l_g = QLabel('G')
l_h = QLabel('H')
l_i = QLabel('I')
self.grid.addWidget(l_a, 0, 0)
self.grid.addWidget(l_b, 0, 1)
self.grid.addWidget(l_c, 0, 2)
self.grid.addWidget(l_d, 1, 0)
self.grid.addWidget(l_e, 1, 1)
self.grid.addWidget(l_f, 1, 2)
self.grid.addWidget(l_g, 2, 0)
self.grid.addWidget(l_h, 2, 1)
self.grid.addWidget(l_i, 2, 2)
self.wid.setLayout(self.grid)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = SurfViewer(app)
ex.setWindowTitle('window')
ex.show()
sys.exit(app.exec_( ))
I get this:
What I would like is instead of the colored line, have the possibility to click and drag vertically (for green lines) and horizontally (for red lines) the grid borders.
I tried something with QSplitter directly, but I end up with:
The Horizontal splits are okay, but the vertical ones are not aligned any more:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
super(SurfViewer, self).__init__()
self.parent = parent
self.setFixedWidth(300)
self.setFixedHeight(100)
self.wid = QWidget()
self.setCentralWidget(self.wid)
# self.grid = QGridLayout()
self.globallayout = QVBoxLayout()
self.split_V = QSplitter(Qt.Vertical)
l_a = QLabel('A')
l_b = QLabel('B')
l_c = QLabel('C')
l_d = QLabel('D')
l_e = QLabel('E')
l_f = QLabel('F')
l_g = QLabel('G')
l_h = QLabel('H')
l_i = QLabel('I')
split_H = QSplitter(Qt.Horizontal)
split_H.addWidget(l_a)
split_H.addWidget(l_b)
split_H.addWidget(l_c)
self.split_V.addWidget(split_H)
split_H = QSplitter(Qt.Horizontal)
split_H.addWidget(l_d)
split_H.addWidget(l_e)
split_H.addWidget(l_f)
self.split_V.addWidget(split_H)
split_H = QSplitter(Qt.Horizontal)
split_H.addWidget(l_g)
split_H.addWidget(l_h)
split_H.addWidget(l_i)
self.split_V.addWidget(split_H)
self.globallayout.addWidget(self.split_V)
self.wid.setLayout(self.globallayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = SurfViewer(app)
ex.setWindowTitle('window')
ex.show()
sys.exit(app.exec_( ))
Update
I think I almost found a solution where a function is used so that whenever the vertical splits are changed, it re-aligns them:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
super(SurfViewer, self).__init__()
self.parent = parent
self.setFixedWidth(300)
self.setFixedHeight(100)
self.wid = QWidget()
self.setCentralWidget(self.wid)
# self.grid = QGridLayout()
self.globallayout = QVBoxLayout()
self.split_V = QSplitter(Qt.Vertical)
l_a = QLabel('A')
l_b = QLabel('B')
l_c = QLabel('C')
l_d = QLabel('D')
l_e = QLabel('E')
l_f = QLabel('F')
l_g = QLabel('G')
l_h = QLabel('H')
l_i = QLabel('I')
self.split_H1 = QSplitter(Qt.Horizontal)
self.split_H1.addWidget(l_a)
self.split_H1.addWidget(l_b)
self.split_H1.addWidget(l_c)
self.split_V.addWidget(self.split_H1)
self.split_H2 = QSplitter(Qt.Horizontal)
self.split_H2.addWidget(l_d)
self.split_H2.addWidget(l_e)
self.split_H2.addWidget(l_f)
self.split_V.addWidget(self.split_H2)
self.split_H3 = QSplitter(Qt.Horizontal)
self.split_H3.addWidget(l_g)
self.split_H3.addWidget(l_h)
self.split_H3.addWidget(l_i)
self.split_V.addWidget(self.split_H3)
self.globallayout.addWidget(self.split_V)
self.wid.setLayout(self.globallayout)
self.split_H1.splitterMoved.connect(self.moveSplitter)
self.split_H2.splitterMoved.connect(self.moveSplitter)
self.split_H3.splitterMoved.connect(self.moveSplitter)
# self.split_H1.splitterMoved
# self.moveSplitter(0,self.split_H1.at )
def moveSplitter( self, index, pos ):
# splt = self._spltA if self.sender() == self._spltB else self._spltB
self.split_H1.blockSignals(True)
self.split_H2.blockSignals(True)
self.split_H3.blockSignals(True)
self.split_H1.moveSplitter(index, pos)
self.split_H2.moveSplitter(index, pos)
self.split_H3.moveSplitter(index, pos)
self.split_H1.blockSignals(False)
self.split_H2.blockSignals(False)
self.split_H3.blockSignals(False)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = SurfViewer(app)
ex.setWindowTitle('window')
ex.show()
sys.exit(app.exec_( ))
However, I still have an issue at the begining - the alignment is not correct :
I don't know How call the function moveSplitter in the __init__
It seems that directly calling moveSplitter (which is a protected method) may be problematic. Using Qt-5.10.1 with PyQt-5.10.1 on Linux, I found that it can often result in a core dump when called during __init__. There is probably a good reason why Qt provides setSizes as a public method for changing the position of the splitters, so it may be wise to prefer it over moveSplitter.
With that in mind, I arrived at the following implementation:
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
...
self.split_H1.splitterMoved.connect(self.moveSplitter)
self.split_H2.splitterMoved.connect(self.moveSplitter)
self.split_H3.splitterMoved.connect(self.moveSplitter)
QTimer.singleShot(0, lambda: self.split_H1.splitterMoved.emit(0, 0))
def moveSplitter(self, index, pos):
sizes = self.sender().sizes()
for index in range(self.split_V.count()):
self.split_V.widget(index).setSizes(sizes)
The single-shot timer is needed because on some platforms the geometry of the window may not be fully initialized before it is shown on screen. And note that setSizes does not trigger splitterMoved, so there is no need to block signals when using it.

Scrolling Text in PyQt?

I'm trying to have text from feedparser scroll across the screen from right to left. I'm using PyQt5, I'm not sure how to go about adding this feature.
What I want to display is below
import feedparser
sports = feedparser.parse('http://rssfeeds.usatoday.com/UsatodaycomSports-TopStories')
for e in sports['entries']:
news = (e.get('title', ''))
I'm looking for a continuous scrolling until all the news headlines are read and then the page is reloaded to get the most recent headlines or just reread whats already there. Thanks!
You can use QTimeLine to show a continously scrolling slice of the news in a label. I implemented it in a little gui to try, if other functions in the app are blocked while QTimeLine is running:
import feedparser
import sys
from PyQt5 import QtWidgets, QtCore
class MyWidget(QtWidgets.QWidget):
def __init__(self, parent = None):
QtWidgets.QWidget.__init__(self, parent)
self.setGeometry(200, 200, 800, 600)
self.textLabel = QtWidgets.QLabel('') # label showing some text
self.uButton = QtWidgets.QPushButton('upper Button')
self.lButton = QtWidgets.QPushButton('lower Button')
self.label = QtWidgets.QLabel('') # label showing the news
self.label.setAlignment(QtCore.Qt.AlignRight) # text starts on the right
self.layout = QtWidgets.QVBoxLayout()
self.layout.addWidget(self.textLabel)
self.layout.addWidget(self.uButton)
self.layout.addWidget(self.lButton)
self.layout.addWidget(self.label)
self.layout.setStretch(0, 3)
self.layout.setStretch(1, 3)
self.layout.setStretch(2, 3)
self.layout.setStretch(3, 1)
self.setLayout(self.layout)
self.timeLine = QtCore.QTimeLine()
self.timeLine.setCurveShape(QtCore.QTimeLine.LinearCurve) # linear Timeline
self.timeLine.frameChanged.connect(self.setText)
self.timeLine.finished.connect(self.nextNews)
self.signalMapper = QtCore.QSignalMapper(self)
self.signalMapper.mapped[str].connect(self.setTlText)
self.uButton.clicked.connect(self.signalMapper.map)
self.signalMapper.setMapping(self.uButton, self.uButton.text())
self.lButton.clicked.connect(self.signalMapper.map)
self.signalMapper.setMapping(self.lButton, self.lButton.text())
self.feed()
def feed(self):
fm = self.label.fontMetrics()
self.nl = int(self.label.width()/fm.averageCharWidth()) # shown stringlength
news = []
sports = feedparser.parse('http://rssfeeds.usatoday.com/UsatodaycomSports-TopStories')
for e in sports['entries']:
news.append(e.get('title', ''))
appendix = ' '*self.nl # add some spaces at the end
news.append(appendix)
delimiter = ' +++ ' # shown between the messages
self.news = delimiter.join(news)
newsLength = len(self.news) # number of letters in news = frameRange
lps = 4 # letters per second
dur = newsLength*1000/lps # duration until the whole string is shown in milliseconds
self.timeLine.setDuration(dur)
self.timeLine.setFrameRange(0, newsLength)
self.timeLine.start()
def setText(self, number_of_frame):
if number_of_frame < self.nl:
start = 0
else:
start = number_of_frame - self.nl
text = '{}'.format(self.news[start:number_of_frame])
self.label.setText(text)
def nextNews(self):
self.feed() # start again
def setTlText(self, text):
string = '{} pressed'.format(text)
self.textLabel.setText(string)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
widget = MyWidget()
widget.show()
sys.exit(app.exec_())
Add PySide2 version:
import feedparser
import sys
from PySide2 import QtWidgets, QtCore
class MyWidget(QtWidgets.QWidget):
def __init__(self, parent = None):
QtWidgets.QWidget.__init__(self, parent)
self.setGeometry(200, 200, 800, 600)
self.textLabel = QtWidgets.QLabel('') # label showing some text
self.uButton = QtWidgets.QPushButton('upper Button')
self.lButton = QtWidgets.QPushButton('lower Button')
self.label = QtWidgets.QLabel('') # label showing the news
self.label.setAlignment(QtCore.Qt.AlignRight) # text starts on the right
self.layout = QtWidgets.QVBoxLayout()
self.layout.addWidget(self.textLabel)
self.layout.addWidget(self.uButton)
self.layout.addWidget(self.lButton)
self.layout.addWidget(self.label)
self.layout.setStretch(0, 3)
self.layout.setStretch(1, 3)
self.layout.setStretch(2, 3)
self.layout.setStretch(3, 1)
self.setLayout(self.layout)
self.timeLine = QtCore.QTimeLine()
self.timeLine.setCurveShape(QtCore.QTimeLine.LinearCurve) # linear Timeline
self.timeLine.frameChanged.connect(self.setText)
self.timeLine.finished.connect(self.nextNews)
self.signalMapper = QtCore.QSignalMapper(self)
self.signalMapper.mapped[str].connect(self.setTlText)
self.uButton.clicked.connect(self.signalMapper.map)
self.signalMapper.setMapping(self.uButton, self.uButton.text())
self.lButton.clicked.connect(self.signalMapper.map)
self.signalMapper.setMapping(self.lButton, self.lButton.text())
self.feed()
def feed(self):
fm = self.label.fontMetrics()
self.nl = int(self.label.width()/fm.averageCharWidth()) # shown stringlength
news = []
sports = feedparser.parse('http://rssfeeds.usatoday.com/UsatodaycomSports-TopStories')
for e in sports['entries']:
news.append(e.get('title', ''))
appendix = ' '*self.nl # add some spaces at the end
news.append(appendix)
delimiter = ' +++ ' # shown between the messages
self.news = delimiter.join(news)
newsLength = len(self.news) # number of letters in news = frameRange
lps = 4 # letters per second
dur = newsLength*1000/lps # duration until the whole string is shown in milliseconds
self.timeLine.setDuration(dur)
self.timeLine.setFrameRange(0, newsLength)
self.timeLine.start()
def setText(self, number_of_frame):
if number_of_frame < self.nl:
start = 0
else:
start = number_of_frame - self.nl
text = '{}'.format(self.news[start:number_of_frame])
self.label.setText(text)
def nextNews(self):
self.feed() # start again
def setTlText(self, text):
string = '{} pressed'.format(text)
self.textLabel.setText(string)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
widget = MyWidget()
widget.show()
sys.exit(app.exec_())

Python Tkinter Graph

I'd like to make a program which takes an integer from user and makes as many entries in a Tkinkter window. Than from those entries take data and make a graph base on them. But when i turn on my program evereything is fine only a graph is wrong. It shows me an empty graph without any data on it, with no title and no "labels names". Here is my code. Please help. I'm using Python 2.7.5, PyDev for Eclipse
# -*- coding: utf-8 -*-
import matplotlib.pyplot as mp
import Tkinter as T, sys
def end():
sys.exit()
def check():
z = e.get()
try:
z = int(z)
e.config(bg = 'green')
e.after(1000, lambda: e.config(bg = 'white'))
x = []
y = []
global x1, y1
x1 = []
y1 = []
l2 = T.Label(main, text = 'X',bg = 'yellow')
l2.pack()
for i in range(0,z):
x.append(T.Entry(main, justify = 'center'))
x[i].pack()
x1.append(x[i].get())
l3 = T.Label(main, text = 'Y', bg = '#3366ff')
l3.pack()
for i in range(0,z):
y.append(T.Entry(main, justify = 'center'))
y[i].pack()
y1.append(y[i].get())
except:
e.config(bg = 'red')
e.after(1000, lambda: e.config(bg = 'white'))
return x1,y1
def graph():
mp.ion()
mp.plot(x1,y1)
mp.title('Wykres')
mp.xlabel('x')
mp.ylabel('y')
mp.draw()
#====================================================================#
y1 = []
x1 = []
z = 0
main = T.Tk()
main.title('GRAPH')
main.geometry('600x600')
main.config(bg = "#3366ff")
e = T.Entry(main,justify = 'center')
l = T.Label(main,text = 'Podaj liczbę parametrów N =',bg = '#3366ff')
b1 = T.Button(main, text = 'OK', command = check)
b2 = T.Button(main, text = 'Rysuj', command = graph)
b = T.Button(main,text = 'Zakończ', command = end)
l.pack()
e.pack()
b1.pack()
b2.pack()
b.pack()
main.mainloop()
GB: x1, x2 have only empty strings. You have to get values from Entry in graph() function when Entry have some value - and remember to convert it from string to integer.
PL: x1, x2 zawierają tylko puste stringi. Musisz pobrać wartości z Entry w funkcji graph() kiedy Entry już zawierają jakieś wartości - i pamiętaj przekonwertować je z napisów na liczby
working code / działający kod
# -*- coding: utf-8 -*-
import matplotlib.pyplot as mp
import Tkinter as T, sys
class Application():
def __init__(self, root):
self.root = root
self.x1 = []
self.y2 = []
self.z = 0
self.root.title('GRAPH')
self.root.geometry('600x600')
self.root.config(bg="#3366ff")
self.e = T.Entry(self.root, justify='center')
self.l = T.Label(self.root, text='Podaj liczbę parametrów N =', bg='#3366ff')
self.b1 = T.Button(self.root, text='OK', command=self.check)
self.b2 = T.Button(self.root, text='Rysuj', command=self.graph)
self.b = T.Button(self.root, text='Zakończ', command=self.end)
self.l.pack()
self.e.pack()
self.b1.pack()
self.b2.pack()
self.b.pack()
#------------------------------------------------------------
def run(self):
self.root.mainloop()
#------------------------------------------------------------
def end(self):
sys.exit()
#------------------------------------------------------------
def check(self):
try:
self.entry_x = []
self.entry_y = []
self.z = int(self.e.get())
self.e.config(bg='green')
self.e.after(1000, lambda: self.e.config(bg='white'))
self.l2 = T.Label(self.root, text='X', bg='yellow')
self.l2.pack()
for i in range(self.z):
self.entry_x.append(T.Entry(self.root, justify='center'))
self.entry_x[-1].pack()
self.l3 = T.Label(self.root, text='Y', bg='#3366ff')
self.l3.pack()
for i in range(self.z):
self.entry_y.append(T.Entry(self.root, justify='center'))
self.entry_y[-1].pack()
except:
self.e.config(bg='red')
self.e.after(1000, lambda: self.e.config(bg='white'))
#------------------------------------------------------------
def graph(self):
self.x1 = []
self.y1 = []
for i in range(len(self.entry_x)):
self.x1.append(float(self.entry_x[i].get()))
for i in range(len(self.entry_y)):
self.y1.append(float(self.entry_y[i].get()))
mp.ion()
mp.plot(self.x1, self.y1)
mp.title('Wykres')
mp.xlabel('x')
mp.ylabel('y')
mp.draw()
#====================================================================#
Application(T.Tk()).run()

Categories