Im creating an application with PyQt5. I wanted to create a widget that lives inside a frame and that the user can move and resize at will. Following this answer i came to the conclusion that i could use QDockWidgets to do this.
Thing is: i want my QDockWidget to only exist and be movable inside a frame of my mainwindow. It seems that setAllowedAreas() could do this restriction for me but it can only be used with QtDockWidgetAreas, and preexisting areas are just default areas of the main window.
So currently my code is like this:
#!/usr/local/bin/pydm
from PyQt5.QtWidgets import QDockWidget
from pydm import Display
class Window(Display): ##Main window class.
def __init__(self, args, macros):
super(Window, self).__init__(None, args, macros,
ui_filename="main.ui")
self.pushButton.clicked.connect(self.createDock)
def createDock(self):
self.dock=QDockWidget()
self.dock.raise_()
self.dock.show()
(pydm is amodule that inherits all classes from PyQt and allows all default functionalities to work just fine.)
The main.ui file created with QtDesigner is just a widget window with a frame and a pushbutton. The generated window is in the image below:
So obviously my DockWidget can go outside the frame. I tried self.dock.setAllowedAreas(self.myFrame) but i got the expected error when clicking the button:
Traceback (most recent call last):
File "./main.py", line 16, in createDock
self.dock.setAllowedAreas(self.frame)
TypeError: setAllowedAreas(self, Union[Qt.DockWidgetAreas, Qt.DockWidgetArea]): argument 1 has unexpected type 'QFrame'
i also tried:
from PyQt5.QtCore import Qt
and in the createDock(self) function:
myArea = Qt.DockWidgetArea(self.frame)
self.dock.setAllowedAreas(myArea)
But i got:
Traceback (most recent call last):
File "./main.py", line 17, in createDock
myArea = Qt.DockWidgetArea(self.frame)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'QFrame'
Looking at the QDockWidgetArea it doesnt look that i can make a custom Area at all. At least not that i could find.
Is there any way at all to achieve the functionality that i want?
Related
A am trying to add a scroll bar that scrolls downwards but it doesn't work. though it works when i do xview so I'm not sure why its not working for yview.
sry for bad grammar.
round_desc_scroll=tk.Scrollbar(root,orient='vertical',command=round_desc_label.yview)
round_desc_scroll.pack(side=tk.RIGHT,fill=tk.Y)
Traceback (most recent call last):
File "/Volumes/AMIN ALI/zorc save after scroll.py", line 134, in <module>
round_desc_scroll=tk.Scrollbar(root, orient='vertical',command=round_desc_label.yview)
AttributeError: 'Entry' object has no attribute 'yview'
Like the error says, an Entry widget does not have a yview method. This is because the Entry widget can only ever display a single line of text. It has an xview method to scroll in the horizontal direction because the data can be longer than the widget.
If you need to display or allow the user to input multiline data, you need to use a Text widget which supports scrolling in both directions.
from tkinter import *
import random
import time
tk=Tk()
canvas=Canvas(tk,width=1000,height=1000)
canvas.pack()
i=0
x1=-50
y1=0
choice=None
canvas.create_text(500, 300, text="Choose one.", font='TNR 20 bold')
def car():
choice='car'
return choice
button1=Button(tk,text='car',width=10,command=car)
button1.grid(row=1,column=5)#I do not see anything wrong here
tk.mainloop()
This is just part of my code if you are wondering why I have so many unused variables.
This is what is says when I run the code:
Traceback (most recent call last):
File "(You dont need to know the file name)", line 180, in
button1.grid(row=1,column=5)
File "C:\Users\()\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 2223, in grid_configure
+ self._options(cnf, kw))
_tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack
You cannot mix pack() and grid()
from the docs:
Warning: Never mix grid and pack in the same master window. Tkinter will happily spend the rest of your lifetime trying to negotiate a solution that both managers are happy with. Instead of waiting, kill the application, and take another look at your code. A common mistake is to use the wrong parent for some of the widgets.
you are calling canvas.pack() but to the same tk object you add a button on which you call the grid() function.
I am trying to make a basic clicker game in Python using Tkinter. I am getting an AttributeError when trying to place a label that was created in another function from the same class (see code snip). The code running the tkinter window is NOT in the main thread, and the main thread is acting as the console. I am running aClass.funcB from the console, AFTER aClass.funcA has already executed.
class aClass:
def funcA(self):
self.aLabel = Label(top)
global window
window = self
def funcB():
global window
self = window
self.aLabel.place(<argsHere>)
The error I am getting is:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<filePathHere>", line 334, in funcB
self.aLabel.place(<argsHere>)
AttributeError: 'NoneType' object has no attribute 'aLabel'
If anyone wants to look at the actual code (that I dont understand parts of myself) please tell me.
EDIT: Here is a link to the github with the actual files https://github.com/LeotomasMC/Click-Clicker
EDIT 2: On a side note, if anyone could tell me how the window actually starts in this instance, that would be great
Try and remove all the self as I think that it keeps it to only that def, because of that funcB doesn't know that aLabel exists.
Methods in Python classes need self as first argument:
def funcB(self):
global window
self = window
self.aLabel.place(<argsHere>)
You need this argument to access aLabel.
What is the use of the wx.App class (apart from what the documentation says), when you can just create a frame and .Show(True) it?
When should a wx.App class be used, or why shouldn't you create a frame and just show it?
You have to create a wx.App. If you try to instantiate wxPython classes before creating the app, it will fail:
>>> import wx
>>> frame = wx.Frame(None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python26\lib\site-packages\wx-2.8-msw-unicode\wx\_windows.py", line 505, in __init__
_windows_.Frame_swiginit(self,_windows_.new_Frame(*args, **kwargs))
wx._core.PyNoAppError: The wx.App object must be created first!
There will always be one, and only one, wx.App. Instantiating it initializes wxPython - creates the window thread, etc.
The wx.App does a bunch of behind the scenes stuff to make your application work. It does the main loop, which is what waits for the user to do something and then responds. You have to have it. As FogleBird mentioned. By the way, you should NOT have more than one. Doing so will cause weird issues, if it works at all.
Sub-classing wx.App is a valid reason when you have to do some extra functionality in your app. This applies for initiating a connection to a database or connecting over a network, loading some external data/files before firing up the main.
class MyApp(wx.App):
def OnInit(self):
# Do some work here
return True
def __init__(self):
main_frame = MyFrame(*args, **kwargs)
main_frame.Show()
def OnExit(self):
# Clean up and close the resources from the OnInit() method
I'm still working on my little Tkinter project which is simple a logging console that prints incoming text from the serial line to a Text Widget with some coloring applied.
One question is open and can be found here: Python Tkinter Text Widget with Auto & Custom Scroll
However, even without manual scrolling (so I'm using self.text.yview(END) to auto-scroll to the bottom after inserting text with self.text.insert(END, str(parsed_line)).
The script actually works but every now and then it throws some "silent" exceptions within the Tkinter thread that does not let the whole application crash:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python26\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
File "C:\Python26\lib\lib-tk\Tkinter.py", line 2813, in set
self.tk.call((self._w, 'set') + args)
TclError: expected floating-point number but got "0.7807017543859649integer but got "end""
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python26\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
File "C:\Python26\lib\lib-tk\Tkinter.py", line 2813, in set
self.tk.call((self._w, 'set') + args)
TclError: invalid command name ".15427224integer but got "end""
It looks as if some method expected a an integer, returns the string integer but got "end" to a method that expected a float which is concatinated with the error message. The float number in that string looks like the position of the scrollbar that I have attached to my text widget:
(...)
scrollbar = Scrollbar(root)
scrollbar.pack(side=RIGHT, fill=Y)
text = Text(wrap=WORD, yscrollcommand=scrollbar.set)
scrollbar.config(command=text.yview)
text.pack(expand=YES, fill=BOTH)
(...)
I have the feeling that it happens when a lot of lines are inserted within a short time. But since I only have one thread interacting with Tkinter this cannot be a threading issue.
I also got very random errors like that before I had applied the str() function to parsed_line in self.text.insert(END, str(parsed_line)).
This is very strange behavior and I'm wondering if anyone could explain what this is about and how to fix it.
Thanks a lot!
mtTkinter allows multithreading with Tkinter, you can get it here:
http://tkinter.unpythonic.net/wiki/mtTkinter
Just import mtTkinter in place of Tkinter. This will allow you to insert text into a Text widget from multiple threads without conflict. I used it for some instant messaging software I wrote and it works wonderfully.