PyQt5.QtWidgets causes problems with backspace in tkinter entry line - python

I have already tried to find an answer to my question, but I haven't been successful.
I do my first try with an GUI with tkinter on Python 3.6
I create a small example for you:
import tkinter as tk
import PyQt5.QtWidgets
RateFenstergrossh=0.75
RateFenstergrossb=0.75
app = PyQt5.QtWidgets.QApplication([]) # the bug doesn't occur without this line
screen_width = app.desktop().screenGeometry().width()
screen_height = app.desktop().screenGeometry().height()
def vp_start_gui():
global root
root = tk.Tk()
top = Toplevel1(root)
root.mainloop()
class Toplevel1:
def __init__(self, top=None):
top.geometry("+%d+%d"%(screen_width/2 - screen_width*RateFenstergrossb/2, screen_height/2 - screen_height*RateFenstergrossh/2))
self.Entry = tk.Entry(top)
self.Entry.pack(padx=20,pady=20)
if __name__ == '__main__':
vp_start_gui()
If you type some characters and try to delete them with backspace a small rectangle appears in the entry line. If you print this character the program prints <0x08>. If I do not use the package import PyQt5.QtWidgets and the funktion PyQt5.QtWidgets.QApplication([]) the bug doesn't occur.
I do not really understand this bug. Maybe somebody can help me with this.

Thanks to the two comments. I have learned never mix tkinter and PyQt. My solution is now.
import tkinter as tk
RateFenstergrossh=0.75
RateFenstergrossb=0.75
def vp_start_gui():
global root
root = tk.Tk()
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
top = Toplevel1(root)
root.mainloop()
class Toplevel1:
def __init__(self, top=None):
top.geometry("+%d+%d"%(screen_width/2 - screen_width*RateFenstergrossb/2, screen_height/2 - screen_height*RateFenstergrossh/2))
self.Entry = tk.Entry(top)
self.Entry.pack(padx=20,pady=20)
if __name__ == '__main__':
vp_start_gui()
Solution: I have to read the screensize with
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()

Related

How to make the ttk.COMBOBOX arrow size larger in Tkinter

I am making a GUI program using Raspberry Pi.
This GUI is made with Tkinter and works only on the touch screen, no mouse and keyboard.
However, the arrow buttons on the COMBOBOX are too small to touch with your fingers.
I used "tkinter.font" to increase the font size, but the font size only increases and the arrow buttons do not increase in size.
How can I increase the size of this arrow button?
How to apply a style doesn't work. My code is below. please help me
import tkinter.ttk
import tkinter.font
class Application:
def __init__(self, parent):
self.parent = parent
self.data = [1,2,3]
self.bigfont = tkinter.font.Font(family="Helvetica",size=30)
root.option_add("*TCombobox*Listbox*Font", self.bigfont)
self.combo()
def combo(self):
self.style = tkinter.ttk.Style()
self.style.configure('W.TCombobox', arrowsize = 1000)
self.cBox = tkinter.ttk.Combobox(self.parent, values = self.data, style = 'W.TCombobox', font=self.bigfont)
self.cBox.current(0)
self.cBox.pack()
if __name__ == '__main__':
root = tkinter.Tk()
root.title("COMBOBOX TEST")
root.geometry("640x400+100+100")
app = Application(root)
root.mainloop()

second window run first how to stop it

when i run python file kill_app its run first 2nd python file(Hb_test.py) then run 1st python on tkinter.i am using vs code and python version is 3.10
see the code below
from tkinter import*
from Lab.Hb_Test import Hba
class kill_App:
def __init__(self,root):
self.root = root
self.root.geometry("1350x700+0+0")
self.root.title("Billing Software")
bg_color = "#074463"
title = Label(self.root,text = "PATHOLAB",bd=12,relief=GROOVE,bg=bg_color,fg="white",
font = ("ALGERIAN",40),pady=2).pack(fill=X)
if __name__=="__main__":
root =Tk()
obj = kill_App(root)
root.mainloop()
****
this is my second
**
**from tkinter import*
from tkinter import ttk
class Hba:
def __init__(self,root):
self.root = root
self.root.geometry("300x70+200+200")
self.root.title("JIBAN PRABHA PATHOLAB")
bg_color = "#074463"
Hb = LabelFrame(self.root,text="BLOOD TEST",font=("ALGERIAN",15,"bold")
,fg="gold",bg=bg_color)
Hb.place(x=0,y=0)
self.hb_neu_lbl = Label(Hb,text="Hb%(sahils) Test",bg=bg_color,fg="white",font=("Bell MT",15,"bold")).grid(row=1,column=1,padx=5,pady=5)
self.hb_neu=Entry(Hb,width=10,font="BellMT 15",bd=5,relief=SUNKEN).grid(row=1,column=2,padx=5,pady=5)
root = Tk()
obj = Hba(root)
root.mainloop()**
**
When Hb_Test is imported, its code will be executed, so the last three lines in the module will create a window:
Hb_Test.py
...
# below lines will create a window
root = Tk()
obj = Hba(root)
root.mainloop()
Note that it is not recommended to create more than one instance of Tk() and execute .mainloop() more than once.
For window other than the main/root window, use Toplevel instead of Tk. For your case, I would suggest that Hba inherits from Toplevel:
import tkinter as tk
class Hba(tk.Toplevel):
def __init__(self, master=None, **kwargs):
super().__init__(master, **kwargs)
self.geometry("300x70+200+200")
self.title("JIBAN PRABHA PATHOLAB")
bg_color = "#074463"
Hb = tk.LabelFrame(self, text="BLOOD TEST", font=("ALGERIAN",15,"bold"), fg="gold", bg=bg_color)
Hb.place(x=0, y=0)
self.hb_neu_lbl = tk.Label(Hb, text="Hb%(sahils) Test", bg=bg_color, fg="white", font=("Bell MT",15,"bold"))
self.hb_neu_lbl.grid(row=1,column=1,padx=5,pady=5)
self.hb_neu = tk.Entry(Hb, width=10, font="BellMT 15", bd=5, relief=tk.SUNKEN)
self.hb_neu.grid(row=1,column=2,padx=5,pady=5)
Note that I have changed from tkinter import * to import tkinter as tk because wildcard import is not recommended as well.
Also don't write code like below:
self.hb_neu_lbl = Label(Hb,text="Hb%(sahils) Test",bg=bg_color,fg="white",font=("Bell MT",15,"bold")).grid(row=1,column=1,padx=5,pady=5)
because self.hb_neu_lbl will be None (result of .grid(...)). Code like below instead:
self.hb_neu_lbl = Label(Hb, text="Hb%(sahils) Test", bg=bg_color, fg="white", font=("Bell MT",15,"bold"))
self.hb_neu_lbl.grid(row=1,column=1,padx=5,pady=5)

How do I open multiple Tk() windows at the same time?

My problem is simple, but i really don't know what the issue is.
I'm trying to open more than one window almost at the same time, but if i do it like that:
from tkinter import *
import threading
import time
class new_window:
def build(self, killtime):
self.w = Tk()
self.w.update()
time.sleep(killtime)
self.w.destroy()
def __init__(self, killtime):
threading.Thread(target=self.build(killtime)).start()
a = new_window(2)
time.sleep(2)
b = new_window(2)
it doesn't behave like: "open, wait, open"
but instead like: "open, wait until killed, wait, open"
What i mean is that the delay starts after the first window is closed, not after the window started. I thought a Thread would help me out, but it didn't.
Hopefully one of you knows how to fix that.
You don't really need to use the threading module.
You can use the .after() method to open a new window a little after.
Here is your code:
from tkinter import *
window = Tk()
window.title("window1")
def open_new_window():
window2 = Toplevel()
window2.title("Window2")
window.after(1000, open_new_window)
window.mainloop()
Hope this helps!
Edit: The code above opens one window, then stops doing anything. If you want new windows to keep opening with a small delay in between, you can use the below code:
from tkinter import *
window = Tk()
window.title("window1")
def open_new_window():
window2 = Toplevel()
window2.title("Window2")
window.after(1000, open_new_window)
open_new_window()
window.mainloop()
Hope this helps!
I did it like this now. But i still marked the Answer of #TheMaker as the Solution, cause its more compact and easier to understand.
from tkinter import *
import threading
import time
from random import *
root = Tk()
root.configure(background='black')
root.attributes("-fullscreen", True)
class new_window:
def build(self, delay, x, y):
self.w = Tk()
self.w.title("")
self.ws = root.winfo_screenwidth() # width of the screen
self.hs = root.winfo_screenheight() # height of the screen
self.w.geometry(f"250x100+{int(round(self.ws/100*x))}+{int(round(self.hs/100*y))}")
self.w.update()
time.sleep(delay)
def __init__(self, delay, x, y):
threading.Thread(target=self.build(delay, x, y)).start()
def rdm(delay, count):
i = 1
while i<=count:
new_window(delay, randint(1, 100), randint(1, 100))
i+=1
rdm(0.02, 100)
root.mainloop()

Debugging my code

I am new to python and am trying to create an application that displays different information like a clock, current news, notice board etc.
I got the clock to work however I am encountering a few bugs. One is that a smaller window launches when the application does. I thought this was something to do with the self.root = tk.Tk() in the initialisation however doing anything to this line produces errors.
The other bug is that while the background image (0.png) used to fill up the entire screen as it is the same size as my monitor, when I added the clock to the application, the image is shifted to the bottom right of the screen, leaving a small white line to the top and left of the screen. I have tried to fix this by messing with the panel.pack changing it to grid and place however both of this did nothing to the lines. I feel like something is overwriting this line.
None of these bugs are showing up in the console and I don't know what to do. Here is the code I am running:
from tkinter import *
from PIL import ImageTk, Image
import os
import time
import tkinter as tk
class App(Tk):
def __init__(self):
self.root = tk.Tk()
self.label = tk.Label(text="",font=('comic',50,'bold'),bg = '#464545',fg = '#1681BE')
self.label.place(height = 206,width = 487, x = 1384, y = 824)
self.update_clock()
self.root.mainloop()
def update_clock(self):
now = time.strftime('%H:%M:%S')
self.label.configure(text=now)
self.root.after(1000, self.update_clock)
root = Tk()
img = ImageTk.PhotoImage(Image.open("0.png"))
panel = Label(root, image = img)
panel.pack()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
app = App()
root.geometry("%dx%d+0+0" % (w, h))
root.mainloop()
I hope someone can find what's wrong with it because I certainly can't!
Since your App class inherit from Tk, you don't need to create another root window. So I gathered all your code inside the App class. When I use an image the side of my screen, I don't see any line at the top or at the left of the screen, so I hope it will work for you as well.
from PIL import ImageTk, Image
import os
import time
import tkinter as tk
class App(tk.Tk):
def __init__(self):
# call the __init__ method of Tk class to create the main window
tk.Tk.__init__(self)
# background image
img = ImageTk.PhotoImage(Image.open("0.png"))
panel = Label(self, image=img)
panel.pack()
# clock
self.label = tk.Label(self, text="", font=('comic',50,'bold'),
bg='#464545', fg='#1681BE')
self.label.place(height=206, width=487, x=1384, y=824)
self.update_clock()
# window geometry
w, h = self.winfo_screenwidth(), self.winfo_screenheight()
self.geometry("%dx%d+0+0" % (w, h))
self.overrideredirect(True)
self.mainloop()
def update_clock(self):
now = time.strftime('%H:%M:%S')
self.label.configure(text=now)
self.after(1000, self.update_clock)
app = App()

Where should i place mainloop?

I have a program written in IDLE3.3 and tkinter where I don't know where to place the mainloop(). The program creates a systray icon that creates a little note if you click on "new note" in the context menu. If there is the line "self.root.mainloop()" at the end of Note.init(), the note is shown, but only one note. if I create a second one, the first note is dead and nothing further happens.
But if I don't call the mainloop() in the init-method, i see that there a several notes created because it is printed in the shell.
So the question is, where should I place the mainloop so that every newly created notw is shown and works? Sorry for that possibly stupid question but I can't figure it out.
from tkinter import *
import sys
from PyQt4.QtGui import *
import threading
class Note():
yellow=["#e7e37c","#d9d574"]
def __init__(self,noteset=None, properties=None):
self.root=Tk()
self.noteset=noteset
self.properties=properties
self.screen_width = self.root.winfo_screenwidth()
self.screen_height = self.root.winfo_screenheight()
print("No initial properties to load => creating new note")
self.notecolor=self.yellow[0]
self.gripcolor=self.yellow[1]
self.root.overrideredirect(1)
self.text=""
self.font="arial"
self.fontsize=10
self.sizeX=250
self.sizeY=200
self.posX=int(self.screen_width/2 - self.sizeX/2)
self.posY=int(self.screen_height/2 - self.sizeY/2)
self.root.wm_geometry("%sx%s+%s+%s" %(self.sizeX, self.sizeY, self.posX, self.posY) )
self.root.wm_attributes("-topmost",1)
self.GUI()
self.bindings()
self.root.mainloop()
def bindings(self):
self.frmGRIP.bind("<ButtonPress-1>", self.StartMove)
self.frmGRIP.bind("<ButtonRelease-1>", self.StopMove)
self.frmGRIP.bind("<B1-Motion>", self.OnMotion)
def StartMove(self, event):
self.startx = event.x
self.starty = event.y
def OnMotion(self, event):
mousex,mousey=self.root.winfo_pointerxy()
self.root.geometry("+%s+%s" % (mousex-self.startx, mousey-self.starty))
def StopMove(self, event):
self.posX = self.root.winfo_x()
self.posY = self.root.winfo_y()
def GUI(self):
self.frmTOP=Frame(master=self.root,height=15)
self.frmBOTTOM=Frame(master=self.root,width=300,height=300)
self.frmGRIP=Frame(self.frmTOP,bg=self.gripcolor,height=15)
self.frmRESIZE=Frame(self.frmBOTTOM,width=300,height=10)
self.frmTEXT=Frame(self.frmBOTTOM,bg=self.notecolor,width=300,height=300)
self.frmRESIZE_empty=Frame(self.frmRESIZE,bg=self.notecolor,height=10)
self.frmRESIZE_grip=Frame(self.frmRESIZE,bg=self.gripcolor,width=10,height=10)
self.frmTOP.pack(fill=X,expand=NO)
self.frmBOTTOM.pack(side=BOTTOM,fill=BOTH,expand=YES)
self.frmGRIP.pack(side=LEFT,fill=X,expand=YES)
self.frmRESIZE.pack(side=BOTTOM,fill=X)
self.frmTEXT.pack(side=BOTTOM,fill=BOTH,expand=YES)
self.frmRESIZE_empty.pack(side=LEFT,fill=X,expand=YES)
self.frmRESIZE_grip.pack(side=LEFT,expand=NO)
self.T=Text(self.frmTEXT,
height=6,width=30,
bd=0,wrap=WORD,pady=3,padx=5,
bg=self.notecolor,undo=1,
font=(self.font,self.fontsize)
)
self.T.insert(END,self.text)
self.T.pack(fill=BOTH,expand=YES)
class Noteset():
def __init__(self):
self.notes = []
def newNote(self):
note=Note(noteset=self)
self.notes.append(note)
print(self.notes)
return note
class Main():
def __init__(self):
self.N=Noteset()
app = QApplication(sys.argv)
trayIcon = QSystemTrayIcon(QIcon("J:\\python\\SimpleNotes.ico"), app)
menu = QMenu()
ActionNewNote = menu.addAction("new Note")
ActionNewNote.triggered.connect(self.newNote)
trayIcon.setContextMenu(menu)
trayIcon.show()
app.exec()
def newNote(self):
self.N.newNote()
Main()
You cannot successfully use Qt and Tkinter together. Also, if you remove Qt from the above you have the additional problem that you should not create more than once instance of Tk.
To answer your specific question, mainloop is normally the very last line of code that you execute. Since it is an infinite loop, any code after you call mainloop won't execute until the main window is destroyed.
The normal structure for a Tkinter application goes something like this:
import Tkinter as tk
class MyApp(...):
def __init__(self, root, ...):
...
...
root = tk.Tk()
myApp(root)
root.mainloop()
Its not a good idea to mix gui frameworks as each of the mainloops block each other, your better off to code the whole thing in one or the other.

Categories

Resources