How can I do in tkinter something similar to a messagebox, but that doesn't have any buttons, including the close, minimize and maximize buttons on top?
I want it to be in a different window (like a message box), and to be able to update the text and close it only within the code.
Is there a way to do something like that?
Make your own. For example:
try: #python3 imports
import tkinter as tk
except ImportError: #python3 failed, try python2 imports
import Tkinter as tk
class Popup(tk.Toplevel):
"""modal window requires a master"""
def __init__(self, master, **kwargs):
tk.Toplevel.__init__(self, master, **kwargs)
self.overrideredirect(True)
self.geometry('300x200+500+500') # set the position and size of the popup
lbl = tk.Label(self, text="Please wait for other players to join ... ")
lbl.place(relx=.5, rely=.5, anchor='c')
# The following commands keep the popup on top.
# Remove these if you want a program with 2 responding windows.
# These commands must be at the end of __init__
self.transient(master) # set to be on top of the main window
self.grab_set() # hijack all commands from the master (clicks on the main window are ignored)
### demo usage:
def open_popup():
root.popup = Popup(root)
# close the popup in 2 seconds
root.after(2000, close_popup)
def close_popup():
root.popup.destroy()
root = tk.Tk()
btn = tk.Button(root, text='Open Modal Window', command=open_popup)
btn.pack()
root.mainloop()
Related
I'm working on numercial simulations in Abaqus 2020 and coded a GUI with Tkinter.
My problem is, that while running the Tkinter code everything works well unitl the start of the mainloop. Then both windows of Tkinter and Abaqus freeze. When I first close the Abaqus window, the Tkinter Window works correctly. I tried sth with threads but wihtout success..
Setup: Windows 10, Abaqus 2020, Python 2.7
here you find a minimal example:
import Tkinter as tk
from Tkinter import *
# Creating master Tkinter window
window = tk.Tk()
window.title('TKINTER-mini')
# window.attributes("-fullscreen", True)
width=1200
window.geometry("1800x1000")
# Frames
frame0 = Frame(window, width=width)
label_Titel = tk.Label(master=frame0, text ='Test', font=('Aerial 15 bold'))
label_Titel.grid(row=0, column = 0)
frame0.grid(row=0, column=2, padx=20, pady=20, ipadx = 20, ipady=20)
window.mainloop()
# window.update()
I'm looking forward to get some help. Thank you in advance!
Greets JBKingPile
I tried
#1
def __init__(self):
import threading
threading.Thread.__init__(self)
def shutdown_ttk_repeat(self):
self.mainroot.eval('::ttk::CancelRepeat')
self.mainroot.destroy()
def __init__(self, parent):
self.mainroot = parent
# self.mainroot.protocol("WM_DELETE_WINDOW", self.shutdown_ttk_repeat)
# self.tabpage()
self.root.after(1000, self.refresh())
self.root.mainloop()
#2
try:
# Tk will crash if pythonw.exe has an XP .manifest
# file and the root has is not destroyed explicitly.
# If the problem is ever fixed in Tk, the explicit
# destroy can go.
try:
gui = gui(window)
window.mainloop()
finally:
window.destroy()
except KeyboardInterrupt:
pass
#3
if __name__ == "__main__":
app = simpleapp_tk(window)
window.mainloop()
I learned how to implement ttk calendar from this post Python Tkinter ttk calendar
All I want is including two ttk calendars button in my GUI interface. One for the 'arrival date' button and another for the 'return date' button. However, after I tried to include these two buttons in my GUI window, my GUI window becomes very laggy and slow to be loaded and it sometimes even freezes. Can someone give me some suggestion on what is the problem here?
Based on the link above, I tried to include on ttk calendar button first and everything works fine and my GUI window works smoothly. However, as long as I have two ttk calendar buttons being included, the whole GUI window is very laggy.
# from stackoverflow
# https://stackoverflow.com/questions/48298195/python-tkinter-ttk-calendar
class MyDateEntry(DateEntry):
def __init__(self, master=None, **kw):
DateEntry.__init__(self, master=master, **kw)
# add black border around drop-down calendar
self._top_cal.configure(bg='black', bd=1)
# add label displaying today's date below
tk.Label(self._top_cal, bg='gray90', anchor='w',
text='Today: %s' % date.today().strftime('%x')).pack(fill='x')
...
...
...
# first button
ttk.Label(self.frame_entry_left_col, text='Arrival Date:').grid(row=6, column=0, padx=5, pady=(5, 0), sticky=tk.W)
self.fldArrivalDate = MyDateEntry(self.color, master=self.frame_entry_left_col, font=("Calibri", 8), background=self.color.secondary, width=17, selectmode='day')
self.fldArrivalDate.grid(row=7, column=0, padx=5, pady=(0, 6))
# second button
ttk.Label(self.frame_entry_left_col, text='Return Date:').grid(row=8, column=0, padx=5, pady=(5, 0), sticky=tk.W)
self.fldReturnDate = MyDateEntry(self.color, master=self.frame_entry_left_col, font=("Calibri", 8), width=17, selectmode='day')
self.fldReturnDate.grid(row=9, column=0, padx=5, pady=(0, 6))
I expect both buttons can work smoothly.
I don't reproduce your slowdown on Windows with Python 3.7. Your example is not really complete enough so what I actually tested is below.
A possible missing cause of the slowup is if you have conflicting pack and grid geometry management in a single frame. We can't see that from the code provided. In the below example you could pack the text widget and see if that causes a problem. In the version of Tkinter with Python 3.7 doing both packa nd grid in the same frame will raise an error but depending on the version of Tk you are using this might not occur on Python 2.7 and at one point this caused a lockup in Tk as the geometry managers fought against each other.
# https://stackoverflow.com/q/56811713/291641
#
# pip install tkcalendar
import sys
import tkinter as tk
import tkinter.ttk as ttk
from tkcalendar import DateEntry
from datetime import date
class MyDateEntry(DateEntry):
def __init__(self, master=None, **kw):
DateEntry.__init__(self, master=master, **kw)
# add black border around drop-down calendar
self._top_cal.configure(bg='black', bd=1)
# add label displaying today's date below
tk.Label(self._top_cal, bg='gray90', anchor='w',
text='Today: %s' % date.today().strftime('%x')).pack(fill='x')
def main(args=None):
root = tk.Tk()
frame = ttk.Frame(root)
row = 0
for name in ['Arrival' , 'Departure']:
label = ttk.Label(frame, text=name + ': ')
cal = MyDateEntry(master=frame, width=17, selectmode='day')
label.grid(row=row, column=0, sticky='news')
cal.grid(row=row, column=1, sticky='news')
row += 1
text = tk.Text(frame)
text.grid(row=row, columnspan=2, sticky='news')
frame.grid_rowconfigure(row, weight=1)
frame.grid_columnconfigure(1, weight=1)
frame.grid(row=0, column=0, sticky='news')
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
I developed a simple Python application doing some stuff, then I decided to add a simple GUI using Tkinter.
The problem is that, while the I call a function called startprocess and begin doing stuff which is processor heavy and the window freezes.
I know it's a common problem and I've already read that I should use multithreads (very complicated, because the function updates the GUI too) or divide my code in different function, each one working for a little time. anyways is there any modification needed in below code to avoid GUI freezing?
import threading
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
import os, datetime, sys, subprocess
import parselog_v1
# diplay messagebox window
def MessageBox(windowLable,msg):
messagebox.showinfo(windowLable, msg)
# check if Dir empty
def checkDirEmpty(work_path):
if os.path.isdir(work_path):
if not os.listdir(work_path):
print ("No Files found in directory")
MessageBox('Log Parser', 'No Files found in directory.')
else:
return True
# launch app in center of screen
def center_window(width=300, height=200):
# get screen width and height
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
# calculate position x and y coordinates
x = (screen_width/2) - (width/2)
y = (screen_height/2) - (height/2)
root.geometry('%dx%d+%d+%d' % (width, height, x, y))
# application frame
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
self.master.title("Log Parser")
def createWidgets(self):
self.Run_Main = tk.Button(self)
self.Run_Main["text"] = "Browse for logs"
self.Run_Main["fg"] = "blue"
self.Run_Main["command"] = self.startProcess
self.Run_Main.pack(side='left',padx=0)
self.QUIT = tk.Button(self)
self.QUIT["text"] = "Quit!"
self.QUIT["fg"] = "red"
self.QUIT["command"] = self.quit
self.QUIT.pack(side='right',padx=5)
def startProcess(self):
global Src_foldername
Src_foldername = filedialog.askdirectory()
Src_foldername = Src_foldername.replace("/", "\\")
print("Source folder: " + Src_foldername)
if checkDirEmpty(Src_foldername):
# process logs
# multithread
print("Processing...")
self.refresh()
threading.Thread(target=parselog_v1.main(Src_foldername))
# scroll text inside application frame
class scrollTxtArea:
def __init__(self, root):
frame = tk.Frame(root)
frame.pack()
self.textPad(frame)
return
class IORedirector(object):
'''A general class for redirecting I/O to this Text widget.'''
def __init__(self, text_area):
self.text_area = text_area
class StdoutRedirector(IORedirector):
'''A class for redirecting stdout to this Text widget.'''
def textPad(self, frame):
# add a frame and put a text area into it
textPad = tk.Frame(frame)
self.text = tk.Text(textPad, height=21, width=68)
self.text.config()
# add a vertical scroll bar to the text area
scroll = tk.Scrollbar(textPad)
self.text.configure(yscrollcommand=scroll.set,background="black", foreground="green")
# pack everything
self.text.pack(side=tk.LEFT, pady=2)
scroll.pack(side=tk.RIGHT, fill=tk.Y)
textPad.pack(side=tk.TOP)
self.text.insert("end", "Begin by selecting log folder..." + "\n")
self.text.configure(state='disabled') # disable text editing
sys.stdout = (self) # to begin logging stdio to GUI
return
def write(self, txt):
self.text.configure(state='normal')
self.text.insert('end', txt)
self.text.configure(state='disabled')
root = tk.Tk()
root.resizable(width=False, height=False)
center_window(500, 300) # launch in center of screen
app = Application(master=root)
scrollFrame = scrollTxtArea(root)
app.mainloop()
root.destroy()
You use thread in wrong way.
First: target= needs function name without () and arguments.
You can assign arguments to args= (it have to be tuple even if you have only one argument)
threading.Thread(target=parselog_v1.main, args=(Src_foldername,) )
Now your code runs parselog_v1.main as normal function, waits for result and it will assign this result as function name to taget= - so you have something like this:
result = parselog_v1.main(Src_foldername)
threading.Thread(target=result)
It stops mainloop so it can't get mouse/keyboard events, refresh window, etc. so it looks like window freeze.
Second: after you create thread correctly you have to start it
my_thread = threading.Thread(target=parselog_v1.main, args=(Src_foldername,) )
my_thread.start()
PyQt :Parent Window not waiting until child window closes. with reference to code shared below ,My welcome class object should wait till first_time class object completely finishes executing , but instead goes ahead and closes it self before first_time object finishes executing .
code :
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PySide.QtCore import QSettings
import sys
from PyQt4 import uic
#importing first configuration class
import configure as config_first
#loading initial settings
settings=QSettings('settings.ini',QSettings.IniFormat)
#loading the ui screens
form_class=uic.loadUiType("screens/firstscreen.ui")[0]
class welcome(QDialog,form_class):
#this signal is emitted when first configuration is done and ready to go
done_and_go_to_use = pyqtSignal()
def __init__(self):
super(welcome, self).__init__()
self.setupUi(self)
self.done_and_go_to_use.connect(self.close)
self.ready_btn.clicked.connect(self.ready)
def ready(self):
if_configured = settings.value('isConfigured', False)
if not if_configured :
first_time=config_first.configureFirst(self)
first_time.show()
self.close()
app = QApplication(sys.argv)
p = welcome()
p.show()
app.exec_()
below is the code for configure.py
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sqlite3
import csv
from PySide.QtCore import QSettings
from PyQt4 import uic
#loading initial settings
settings=QSettings('settings.ini',QSettings.IniFormat)
#loading ui screens
form_class=uic.loadUiType("screens/config_first.ui")[0]
#database connecting
con = sqlite3.connect("local.db")
cur = con.cursor()
cur.execute("CREATE TABLE if not exists marks (student_id int,student_name varchar(200));")
class configureFirst(QDialog,form_class):
done_configuring=pyqtSignal()
try_again=pyqtSignal()
def __init__(self,parent=None):
super(configureFirst, self).__init__(parent)
self.setupUi(self)
self.ok_btn.clicked.connect(self.ok_clicked)
self.cancel_btn.clicked.connect(self.cancel_clicked)
self.try_again.connect(self.ok_clicked)
self.done_configuring.connect(self.cancel_clicked)
self.show()
def ok_clicked(self):
file_select=QFileDialog.getOpenFileName(self,"open file","/")
if file_select:
with open(file_select, 'rb') as f:
reader = csv.reader(f)
ed = list(reader)
for row in ed:
if "name" not in row or "id" not in row:
cur.execute("Insert into marks Values (?,?);",(row[0],row[1]))
con.commit()
settings.setValue("isConfigured",True)
self.done_configuring.emit()
else:
#if recurssion is used the no of time it has to close increases and leads to integration problems
self.try_again.emit()
def cancel_clicked(self):
if_configured=settings.value("isConfigured")
if if_configured:
self.close()
else:
QMessageBox.critical(self,"PerfAnalyser","You Need to Configure For PerfAnalyser To Work")
def closeEvent(self,event):
#this method is triggered when 'X' is clicked i.e close button is clicked at the upper right corner
if_configured = settings.value("isConfigured")
if if_configured:
event.accept()
else:
QMessageBox.critical(self, "PerfAnalyser", "You Need to Configure For PerfAnalyser To Work")
event.ignore()
Thanks for the help in advance ...
I will try to help out since I notice few people have seen your post. I have had this happen a long time ago so I need a reminder, but I was unable to get your code running, I also tried to recreate your ui files and the screens directory but I was not successful. However, maybe the following is still useful.
In my working code, any time I needed to create a subwindow, I executed subwindows as follows from the main window's module:
dlg = SubWindowModuleName.StartSub()
dlg.exec_()
This will execute the subwindow and waits for it to close. Then, on the subwindow module (SubWindowModuleName in the above code, "configure" for you), I did this:
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName(_fromUtf8("Dialog"))
Dialog.resize(982, 521)
... # here I build the window (I noticed that you import UI files which is a much better way of doing this)
...
class StartSub(QtGui.QDialog, Ui_Dialog):
def __init__(self,parent=None):
QtGui.QDialog.__init__(self,parent)
self.setupUi(self)
Hy guys,
in my executable program there is a toolbar. Well, the user decides to move the toolbar. Now the toolbar is floating. I know I have to conntect the floating-signals that is emittted when the toolbar ist arranged by the user. How can I save the new position of the toolbar? I know the method of adding the toolbar to the main window with a position:self.addToolBar( Qt.LeftToolBarArea , toolbar_name). In the handle_floating()-method you see what I want: There I want to get the position currently, but how? You also see I have just added one member variable, named self.toolbar_pos, to hold the position of the toolbar. My idea is, when application is terminated I want to serialize this value to a file, and later, when application is ran again its will read that file and set the toolbar accordingly. But this is no problem. Currently I don't have no idea to get the position of the toolbar.
I need your help :)
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.toolbar_pos = None
self.initUI()
def initUI(self):
exitAction = QtGui.QAction(QtGui.QIcon('exit24.png'), 'Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.triggered.connect(QtGui.qApp.quit)
self.toolbar = QtGui.QToolBar(self)
self.toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
self.addToolBar(self.toolbar )
self.toolbar.addAction(exitAction)
self.toolbar.setAllowedAreas(QtCore.Qt.TopToolBarArea
| QtCore.Qt.BottomToolBarArea
| QtCore.Qt.LeftToolBarArea
| QtCore.Qt.RightToolBarArea)
self.addToolBar( QtCore.Qt.LeftToolBarArea , self.toolbar )
self.toolbar.topLevelChanged.connect(self.handle_floating)
def handle_floating(self, event):
# The topLevel parameter is true
# if the toolbar is now floating
if not event:
# If the toolbar no longer floats,
# then calculate the position where the
# toolbar is located currently.
self.toolbar_pos = None
print "Get position: ?"
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.setGeometry(300, 300, 300, 200)
ex.setWindowTitle('Toolbar example')
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The QMainWindow class already has APIs for this: i.e. saveState and restoreState. These can be used to save and restore the state of all the toolbars and dock-widgets in your application.
To use them, you first need to make sure that all your toolbars and dock-widgets are given a unique object-name when they are created:
class Example(QtGui.QMainWindow):
...
def initUI(self):
...
self.toolbar = QtGui.QToolBar(self)
self.toolbar.setObjectName('foobar')
Then you can override closeEvent to save the state:
class Example(QtGui.QMainWindow):
...
def closeEvent(self, event):
with open('/tmp/test.conf', 'wb') as stream:
stream.write(self.saveState().data())
(NB: I've just used a temporary file here for testing, but it would obviously be much better to use something like QSettings in your real application).
Finally, you can restore the state that was saved previously:
class Example(QtGui.QMainWindow):
def __init__(self, parent=None):
...
self.initUI()
try:
with open('/tmp/test.conf', 'rb') as stream:
self.restoreState(QtCore.QByteArray(stream.read()))
except IOError:
pass