Scrollbar for a menu - python

Recently I started to work for a school project. This project has to be an app which is created using python.
Everything worked very well, without problems , but I have a blocking point now.
For the main menu of my app, I want to add a scrollbar in the right side of the interface.
This scrollbar will be used to navigate through photos, buttons and some labels.
This is the code:
import sys
print(sys.executable)
import tkinter as tk
from functools import partial
from tkinter import *
from tkinter import messagebox
from PIL import Image, ImageTk
from QRcodepage import QRcode
class ThePage():
def pageMain(self):
MainPageClass=tk.Toplevel()
MainPageClass.geometry('500x500')
MainPageClass.title('MainPage')
MainPageClass.resizable(0,0)
MainPageClass.configure(bg='#C97E48')
#create hamburger menu
def toggle_win():
f1=Frame(MainPageClass,width=300,height=500,bg='#262626')
f1.place(x=300,y=0)
#create the rest of the buttons
def bttn(x,y,text,bcolor,fcolor,cmd):
def on_entera(e):
myButton1['background']=bcolor #ffcc66
myButton1['foreground']='#ab6038' #000d33
def on_leavea(e):
myButton1['background']=fcolor
myButton1['foreground']='#262626'
myButton1=Button(f1,text=text,width=24,height=2,fg='#262626'
,border=0,bg=fcolor,activeforeground='#262626'
,activebackground=bcolor,command=cmd)
myButton1.bind("<Enter>",on_entera)
myButton1.bind("<Leave>",on_leavea)
myButton1.place(x=x,y=y)
def closeWindow():
#newvar=createlogin.tkLogin
#btn=Button(MainPageClass,command=newvar.withdraw)
#btn.pack()
pass
bttn(13,80,'HOME','#0f9d9a','#14c4c0',None)
bttn(13,140,'TRAINER','#0f9d9a','#14c4c0',None)
bttn(13,200,'NUTRITIONAL PLAN','#0fd9da','#14c4c0',None)
bttn(13,260,'PHYSICAL EVALUATION','#0fd9da','#14c4c0',None)
bttn(13,320,'CHOOSE GYM','#0fd9da','#14c4c0',None)
bttn(13,380,'LOG OUT','#0fd9da','#14c4c0',closeWindow)
def dele():
f1.destroy()
#global img2
#img2=ImageTk.PhotoImage(Image.open('x.png'))
Button(f1,text='X',command=dele).place(x=5,y=10)
#Creating header using Canva function
def code():
code=QRcode()
code.openQR()
w,h=(550,100)
canvas=tk.Canvas(MainPageClass,height=h,width=w)
canvas.pack()
bg=tk.PhotoImage(file="headerbackground.png")
bg_1=tk.Label(MainPageClass,image=bg)
bg_1.place()
Logo=Image.open('C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\Logo2.png')
LogoResiz=Logo.resize((100,100))
LogoRend=ImageTk.PhotoImage(LogoResiz)
LogoLabel=Label(MainPageClass,image=LogoRend)
LogoLabel.place(relx=0,rely=0)
photoHamburger=PhotoImage(file=r"C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\hamburger.png")
photoHamburgerResize=photoHamburger.subsample(7,7)
Hamburgerbtn=tk.Button(MainPageClass,image=photoHamburgerResize,command=toggle_win,text='Login',bd='0')
Hamburgerbtn.place(relx=0.9,rely=0.1,anchor=CENTER)
#This is the end of our code for the Canva area
sb = Scrollbar(MainPageClass,orient=VERTICAL)
sb.pack(side = RIGHT, fill ='y')
TitleLabel=tk.Label(MainPageClass,text='Welcome to your digital gym friend',bg="#C97E48",font='Helvetica 14 bold',xscrollcomand=sb.set)
TitleLabel.place(relx=0.18,rely=0.3)
QRbutton=tk.Button(MainPageClass,text='QR Code',bd='4',command=code,xscrollcomand=sb.set)
QRbutton.place(relx=0.45,rely=0.38)
photoYogaclass=PhotoImage(file=r"C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\yoga.PNG")
photoYogaResize=photoYogaclass.subsample(2,2)
YogaLabel=tk.Label(MainPageClass,image=photoYogaResize,border=0,xscrollcomand=sb.set)
YogaLabel.place(relx=0.1,rely=0.5)
YogaText=tk.Label(MainPageClass,text='Yoga Class',border=0,bg='#C97E48', foreground='white',font=('Arial',14),xscrollcomand=sb.set)
YogaText.place(relx=0.13,rely=0.7)
photoJoin=PhotoImage(file=r'C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\JoinButton.PNG')
photoJoinResize=photoJoin.subsample(1,1)
JoinButton=tk.Button(MainPageClass,image=photoJoinResize,command=None,bd='0',bg="#C97E48",xscrollcomand=sb.set)
JoinButton.place(relx=0.5,rely=0.5)
photoJogging=PhotoImage(file=r'C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\Jogging.PNG')
photoJoggingResize=photoJogging.subsample(2,2)
JoggingLabel=tk.Label(MainPageClass,image=photoJoggingResize,border=0,xscrollcomand=sb.set)
JoggingLabel.place(relx=0.1,rely=0.8)
JoggingText=tk.Label(MainPageClass,text='Jogging Class',border=0,bg='#C97E48', foreground='white',font=('Arial',14),yscrollcomand=sb.set)
JoggingText.place(relx=0.13,rely=1.1)
mainloop()
Do you can help to create a scrollbar which will help me scrolling through the interface?
Thanks!!!!

Related

Tkinter bind event isn't calling function

I have this code:
from tkinter import *
class logic():
def createComponent(self, event):
print("{0},{1}".format(event.x,event.y))
class gui(logic):
window = Tk()
obj = logic()
def initGui(self):
gui.window.mainloop()
def onClick(self):
gui.window.bind("<Button-1>",gui.obj.createComponent)
obj2 = gui()
obj2.initGui()
while True:
obj2.onClick()
In theory this code should print mouse coordinates on lmb click but "createComponent" isn't called for some reason (also no errors). What Im doing wrong?
Fixed the code:
window.mainloop() is already a loop putting it in while True breaks the code
The classes were setup wrong
from tkinter import *
window = Tk()
def createComponent(event):
print("{0},{1}".format(event.x,event.y))
window.bind("<Button-1>", createComponent)
window.mainloop()
OOP:
from tkinter import *
class windFuncs:
def createComponent(event):
print("{0},{1}".format(event.x,event.y))
class wind(Tk):
pass
window = wind()
window.bind("<Button-1>", windFuncs.createComponent)
window.mainloop()
You may wish to put createComponent in class wind

Embed a PyQtGraph in Qt Designer GUI

I have a QtGraph plot and I want to show it in a QLabel, Qwidget or Graphicsview in a GUI that I made in Qt Designer, but I can't find a direct way that shows that graph. I am streaming a video from a camera and I could easily show it in my GUI, but I am struggling with this one.
The problem is in showing.
#These are the libraries which have been used in the app.
import sys
import numpy as np
import cv2
import pyqtgraph as pg
import datetime
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication , QMainWindow
from PyQt5.uic import loadUi
from PyQt5 import QtGui
#this is the main class for this app and get the visual GUI from QtDesigner
class VideoStream(QMainWindow):
def __init__(self):
super(VideoStream , self).__init__()
loadUi('VideoStream.ui',self)
self.image= None
#self.l_values is the place that we collect the intensity values for each frame
self.l_values = []
#This is a button to set the geometry of our mask for the specific zone of lightness
self.Apply_Button.clicked.connect(self.Geometry)
#this button save the maximum values of the specific zone in a text file
#self.Save_Button.clicked.connect(self.save_data)
self.startButton.clicked.connect(self.start_webcam)
self.stopButton.clicked.connect(self.stop_webcam)
#these two variables are the height and width of our camera.
#With different cameras this part should be changed.
self.cameraHeight=480
self.cameraWidth=640
#This function shows the stream in the GUI we created by qtdesigner
def displayImage(self,img,window=1):
qformat=QtGui.QImage.Format_Grayscale8
outImage=QtGui.QImage(img, img.shape[1],img.shape[0],qformat)
self.imgLabel.setPixmap(QtGui.QPixmap.fromImage(outImage))
self.imgLabel.setScaledContents(True)
#for the seperate canvas you should click on the move button in that window once
def displayHist(self,img, window=1):
self.avr = int(np.average(self.image)*25)
self.avrage=np.array([self.avr])
if self.l<=self.bufferSize:
self.plt.setRange(xRange=[max(self.l- 100, 0), self.l])
self.data[self.l:self.l+self.n] = self.avrage
self.curve.setData(self.data)
print(self.l)
self.l = (self.l+self.n)
if self.l%100==0:
if self.l>=100:
print("y ",self.k,np.max(self.data[self.l-100:self.l]))
self.k=self.k+1
elif self.l==0:
print("- ",self.k,np.max(self.data[-(100-self.l):]))
else:
print("n ",self.k,max(np.max(self.data[-(100-self.l):]),np.max(self.data[:self.l])))
self.k=self.k+1
self.line.setValue(self.l)
if self.l>self.bufferSize:
self.plt.setRange(xRange=[max(self.bufferSize- 100, 0), self.bufferSize])
for j in range(self.bufferSize-1):
self.data[j]=self.data[j+1]
self.data[-1]=self.avrage
self.curve.setData(self.data)
self.l = (self.l+self.n)
self.line.setValue(self.bufferSize)
#this is the place that I don't have any idea what to do

Tkinter canvas PhotoImage is not appearing

I have a problem with my code. I am creating a small video game called Lumanite. I have created the homepage and have started the graphics generation, but I have run into a bug. I am using Python 3.3 and am on a Win 10 laptop. I run the program through a run file, which accesses the main_game file that uses the classes outlined in a separate file, spritesclasses. I am trying to make a sprite appear. Here is the code for the main_game file and the spritesclasses file. (They import the canvas and root from a MENU file)
#SPRITES
from tkinter import *
from GUI_FILE import canvas, root
from OPENING_FILE import show, hide
class Sprite():
def __init__(self, photoplace):
self.orgin = photoplace
self.photo = PhotoImage(file=photoplace)
self.w = self.photo.width()
self.h = self.photo.height()
def draw(self):
self.sprite = canvas.create_image(self.h, self.w, image=self.photo)
And the MAIN_GAME file:
#Main Game File:
from tkinter import *
from OPENING_FILE import show, hide
from GUI_FILE import root, canvas
from spritesclasses import *
def start_game():
genterrain()
def genterrain():
test = Sprite("logo.gif")
test.draw()
And the sprites are not appearing. No error or anything. Please help me. I will supply you with information at a further notice.
This is a known but tricky issue. You can read about it in Why do my Tkinter images not appear? I've implemented one possible solution below:
from tkinter import *
class Sprite():
def __init__(self, photoplace):
self.photo = PhotoImage(file=photoplace)
self.w = self.photo.width()
self.h = self.photo.height()
self.sprite = None
def draw(self):
canvas = Canvas(root, width=self.w, height=self.h)
canvas.pack()
self.sprite = canvas.create_image(0, 0, anchor=NW, image=self.photo)
def start_game():
genterrain()
def genterrain():
sprite = Sprite("logo.gif")
sprite.draw()
sprites.append(sprite) # keep a reference!
root = Tk()
sprites = []
start_game()
root.mainloop()
The assignment self.photo = PhotoImage(file=photoplace) isn't a sufficient reference as the object test goes out of scope when genterrain() returns and is garbage collected, along with your image. You can test this by commenting out the line sprites.append(sprite) and see your image disappear again.
Also, it wasn't clear why you were positioning the image at it's own width and height -- the first to arguments to create_image() are the X and Y position. I moved canvas creation into draw() so I could size the canvas to the image but that's not a requirement of the visibility fix.

I want to toggle a real pushbutton and display it on tkinter GUI

I want to toggle a pushbutton and show its changes on a label using tkinter.
If I press the button it shows "on" on the label and when I press again it shows "off" on the label
So I try these codes and If I'm trying the wrong code please help me write the correct using tkinter.
I have a problem in combining this code
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setup(22,GPIO.IN,up_down=GPIO.PUD_UP)
while(1):
if GPIO.input(22)==1:
if bs == False :
x.set("on")
bs=True
sleep(0.5)
else:
x.set("off")
bs=False
sleep(0.5)
This works okay but I want to connect it to a GUI label to print on it on or off.
Here is the tkinter code
import tkinter.*
root = tk()
x = StringVar()
s=Label(root,textvariable=x)
s.grid(column=0,row=0)
root.mainloop()
When I try to combine it I make it like this
from Tkinter import *
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setup(7,GPIO.IN)
b=False
def check_button1():
if GPIO.input(7)== 1:
if b == False :
labelText1.set("on")
print"on"
b=True
time.sleep(0.5)
else:
labelText1.set("off")
print"off"
b=False
time.sleep(0.5)
mamdouh.after(10,check_button1)
mamdouh = Tk()
labelText1 = StringVar()
x1 = Label(mamdouh,textvariable=labelText1)
x1.config(font=('Helvetica',25,'bold'))
x1.grid(row=0,column=0)
mamdouh.title("mamdouh")
mamdouh.geometry('1200x700')
mamdouh.after(10,check_button1)
mamdouh.mainloop()
but it didn't works it keeps blank every time I press the push button actually If it works well I will put 17 push button
I think that the problem is in placing this if statment on the right place and placing the b variable in it's right place and I think also there is a problem between this if statment and tkinter because I tried this code wich works perfect but it is not toggling the push button so I want to change this lets add this code here also :
from Tkinter import *
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(7,GPIO.IN)
def check_button1():
if(GPIO.input(7) == GPIO.LOW):
labelText1.set("on")
else:
labelText1.set("off")
mamdouh.after(10,check_button1)
mamdouh = Tk()
labelText1 = StringVar()
x1 = Label(mamdouh,textvariable=labelText1)
x1.config(font=('Helvetica',25,'bold'))
x1.grid(row=0,column=0)
mamdouh.title("mamdouh")
mamdouh.geometry('1200x700')
mamdouh.after(10,check_button1)
mamdouh.mainloop()
So how I can make this toggle push button on an Label?
Your problem is recognizing button down and button up events. Your OS mouse driver does this for your mouse buttons. If your GPIO module does not do this for you, you will have to detect these events by comparing the current state to the previous state. (I am ignoring here any possible need to 'de-bounce' the button.) You are sort of trying to do this with the time.sleep(.5) calls, but do not use time.sleep in gui code.
Your driver should be self-contained and independent of any tk widgets other than the root needed for .after. For multiple buttons, you will need your own GPIOButton class. Your code that works is a starting point. Tkinter allows you to tie a command to button-up events. Your class init should similarly take up and or down event commands (callbacks).
Here is something untested that might get you started.
class GPIOButton:
def __init__(self, master, buttons, command_down=None, command_up=None):
self.master = master
self.buttons = buttons
self.command_down = command_down
self.command_up = command_up
GPIO.setmode(GPIO.BOARD)
for button in buttons:
GPIO.setup(button, GPIO.IN)
self.state = [GPIO.HIGH] * len(buttons) # best initial value?
self.check_buttons() # or call this elsewhere
def check_buttons(self):
for i, button in enumerate(self.buttons):
oldstate = self.state[i]
newstate = GPIO.input(button)
if oldstate != newstate:
self.state[i] = newstate
command = (self.command_down if newstate==GPIO.LOW
else self.command_up)
command(button)
self.master.after(10, self.check_button)
Let me preface my answer with a disclaimer—I don't have a Raspberry Pi, so couldn't verify this works with the real thing. For testing I used a proxy class that simulates random button pressing. You may have to adjust the DELAY value depending on how fast the GPIO interface works.
However, I have put commented-out code in near the top showing what I think you would need to use based on of doing so in your code.
try:
import Tkinter as tk
import tkFont
except ImportError: # Python 3
import tkinter as tk
import tkinter.font as tkFont
#import RPi.GPIO as GPIO
#
#GPIO.setmode(GPIO.BOARD)
#
#class GPIOButton(object):
# """ Encapsulates GPIO button interface. """
# def __init__(self, pin):
# self.pin = pin
# self.status = 0
# GPIO.setup(pin, GPIO.IN)
#
# def update_status(self):
# self.status = GPIO.input(pin) == GPIO.LOW
### Proxy class since I don't have a Rasperry Pi. ###
import random
class GPIOButton(object):
def __init__(self, pin):
self.pin = pin
self.status = 0
def update_status(self):
if not random.randint(0, 99) % 20: # occassionally toggle status
self.status = not self.status
class App(tk.Frame):
STRIDE = 8
DELAY = 100 # delay in millsecs between button status updates
def __init__(self, gpio_buttons, master=None):
tk.Frame.__init__(self, master)
self.grid()
self.gpio_buttons = gpio_buttons
self.create_widgets()
self.after(self.DELAY, self.update_buttons, self.DELAY) # start updates
def create_widgets(self):
self.btn_font = tkFont.Font(family="Helvetica", size=12, weight='bold')
self.gui_buttons = []
for i, button in enumerate(self.gpio_buttons):
is_pressed = tk.BooleanVar()
is_pressed.set(False)
radiobutton = tk.Radiobutton(self,
text=format(i+1, '02d'),
font=self.btn_font,
value=True,
variable=is_pressed,
relief=tk.RIDGE)
row, col = divmod(i, self.STRIDE)
radiobutton.grid(column=col, row=row)
self.gui_buttons.append(is_pressed)
def update_buttons(self, delay):
for i, gpio_button in enumerate(self.gpio_buttons):
previous_status = gpio_button.status
gpio_button.update_status()
if gpio_button.status != previous_status:
self.gui_buttons[i].set(gpio_button.status)
self.after(delay, self.update_buttons, delay) # rinse and repeat
gpio_buttons = [GPIOButton(pin) for pin in range(16)]
app = App(gpio_buttons)
app.master.title('Rasberry Pi Buttons')
app.mainloop()
Here's what the simulation looks like running on my Windows computer:

Displaying TkInter and OpenCV windows on the same time

I am working to extend this solution given to me previously.
The user can draw randomly using the mouse on a TkInter Canvas widget, after that, the same curves with the same pixels coordinates are drawn on the OpenCV window.
I want to modify that solution so that the TkInter Canvas and the OpenCV window must be shown in the same time: each time the suer finishes drawing one curve on TkInter it is immediately redrawn on the OpenCV window.
Is there a way to fulfill this goal ?
Thank you in advance for any help.
This is arguably even easier to do than to draw all lines in OpenCV later.
I'd make the MaClasse class only make a blank image, open a window and show it on initiation, and give it a method to draw a single line and show the image again.Then you can create a MaClasse object in Test and draw a line in OpenCV each time you draw a line in Tkinter. Then you won't even need to save all lines you've drawn (you can completely remove self.liste).
from Tkinter import *
import numpy as np
import cv2
class Test:
def __init__(self):
self.b1="up"
self.xold=None
self.yold=None
self.liste=[]
self.maclasse = MaClasse()
def test(self,obj):
self.drawingArea=Canvas(obj)
self.drawingArea.pack()
self.drawingArea.bind("<Motion>",self.motion)
self.drawingArea.bind("<ButtonPress-1>",self.b1down)
self.drawingArea.bind("<ButtonRelease-1>",self.b1up)
def b1down(self,event):
self.b1="down"
def b1up(self,event):
self.b1="up"
self.xold=None
self.yold=None
self.liste.append((self.xold,self.yold))
def motion(self,event):
if self.b1=="down":
if self.xold is not None and self.yold is not None:
event.widget.create_line(self.xold,self.yold,event.x,event.y,fill="red",width=3,smooth=TRUE)
self.maclasse.dessiner_ligne(self.xold,self.yold,event.x,event.y)
self.xold=event.x
self.yold=event.y
self.liste.append((self.xold,self.yold))
class MaClasse:
def __init__(self):
self.s=600,600,3
self.ma=np.zeros(self.s,dtype=np.uint8)
cv2.namedWindow("OpenCV",cv2.WINDOW_AUTOSIZE)
cv2.imshow("OpenCV",self.ma)
def dessiner_ligne(self, xold, yold, x, y):
cv2.line(self.ma,(xold, yold),(x,y),[255,255,255],2)
cv2.imshow("OpenCV",self.ma)
if __name__=="__main__":
root = Tk()
root.wm_title("Test")
v = Test()
v.test(root)
root.mainloop()
Since the above code using a Tkinter window and a OpenCV window does not work for you, you could also show the OpenCV image in a Tkinter Toplevel window.
from Tkinter import *
import numpy as np
import cv2
import Image, ImageTk
class Test:
def __init__(self, parent):
self.parent = parent
self.b1="up"
self.xold=None
self.yold=None
self.liste=[]
self.maclasse = MaClasse(self.parent)
def test(self):
self.drawingArea=Canvas(self.parent)
self.drawingArea.pack()
self.drawingArea.bind("<Motion>",self.motion)
self.drawingArea.bind("<ButtonPress-1>",self.b1down)
self.drawingArea.bind("<ButtonRelease-1>",self.b1up)
def b1down(self,event):
self.b1="down"
def b1up(self,event):
self.b1="up"
self.xold=None
self.yold=None
self.liste.append((self.xold,self.yold))
def motion(self,event):
if self.b1=="down":
if self.xold is not None and self.yold is not None:
event.widget.create_line(self.xold,self.yold,event.x,event.y,fill="red",width=3,smooth=TRUE)
self.maclasse.dessiner_ligne(self.xold,self.yold,event.x,event.y)
self.xold=event.x
self.yold=event.y
self.liste.append((self.xold,self.yold))
class MaClasse:
def __init__(self, parent):
self.s=600,600,3
self.ma=np.zeros(self.s,dtype=np.uint8)
self.top = Toplevel(parent)
self.top.wm_title("OpenCV Image")
self.label = Label(self.top)
self.label.pack()
self.show_image()
def dessiner_ligne(self, xold, yold, x, y):
cv2.line(self.ma,(xold, yold),(x,y),[255,255,255],2)
self.show_image()
def show_image(self):
self.im = Image.fromarray(self.ma)
self.imgtk = ImageTk.PhotoImage(image=self.im)
self.label.config(image=self.imgtk)
if __name__=="__main__":
root = Tk()
root.wm_title("Test")
v = Test(root)
v.test()
root.mainloop()

Categories