Python tkinter Canvas Not Doing Anything - python

I'm trying to make a grid with a canvas using tkinter and after I made some change the lines stopped being drawn. I'm not sure what I did but it might have to do with how the Canvas object is nested in the Frame object, but it was working just fine like that at one point.
I also tried using shapes and couldn't get them to draw.
from tkinter import *
class Application(Frame):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.canvas = CanvasClass()
class CanvasClass(Canvas):
def __init__(self):
super().__init__()
self.CanvasHeight = 600
self.CanvasWidth = 800
self.c = Canvas(width=self.CanvasWidth, height=self.CanvasHeight)
self.CreateBackground(20)
self.c.pack(expand=True)
def CreateBackground(self, d):
print(self.CanvasHeight)
print(self.CanvasWidth)
for x in range(d, self.CanvasWidth, d):
print(x)
self.create_line(x, 0, x, self.CanvasHeight)
root = Tk()
root.title = "TESTING"
app = Application()
app.canvas.create_polygon(50,200,50,200)
root.mainloop()

from tkinter import *
class Application(Frame):
def __init__(self,p):
super().__init__(p)
self.initUI()
def initUI(self):
self.canvas = CanvasClass(self)
self.canvas.pack()#1
class CanvasClass(Canvas):
def __init__(self,p):#2
super().__init__(p)
self.CanvasHeight = 600
self.CanvasWidth = 800
self.c = Canvas(width=self.CanvasWidth, height=self.CanvasHeight)
self.CreateBackground(20)
self.c.pack(expand=True)
def CreateBackground(self, d):
print(self.CanvasHeight)
print(self.CanvasWidth)
for x in range(d, self.CanvasWidth, d):
print(x)
self.create_line(x, 0, x, self.CanvasHeight)
root = Tk()
root.title = "TESTING"
app = Application(root)
app.canvas.create_polygon(50,200,50,200)
app.pack()#3
root.mainloop()
you forgot to add the parent and insert it into the window I have used pack() you can change if you want. and I got grids of lines in the window at the bottom when I execute after packing

Related

How can I create new buttons with buttons and plot them in QGraphicScene with an array in PyQt5

I have an application where I have several button widgets on a QGraphicScene and I am trying to make this button widgets to make new buttons on QGraphicScene when they are clicked.
My code is as follows:
buttons = []
class SeveralButtons(QtWidgets.QWidget):
def __init__(self,id,x,y):
super(SeveralButtons,self).__init__()
self.id = id
self.x = x
self.y = y
self.setGeometry(x,y,1,1)
self.button1 = QtWidgets.QPushButton("B1")
self.button2 = QtWidgets.QPushButton("B2")
self.button1.clicked.connect(self.p1b)
self.severalButtonsLayout = QtWidgets.QGridLayout()
self.severalButtonsLayout.addWidget(self.button1, 0,0,)
self.severalButtonsLayout.addWidget(self.button2, 0,1,)
self.setLayout(self.severalButtonsLayout)
def p1b(self):
ph = SeveralButtons(0,self.x-200,self.y-200)
buttons.append(ph)
UiWindow._scene.addWidget(ph)
And my main class is like this:
class UiWindow(QtWidgets.QMainWindow):
factor = 1.5
def __init__(self, parent=None):
super(UiWindow, self).__init__(parent)
self.setFixedSize(940,720)
self._scene = QtWidgets.QGraphicsScene(self)
self._view = QtWidgets.QGraphicsView(self._scene)
self._view.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
self._view.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self._view.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.initButtons()
self.setCentralWidget(self._view)
def initButtons(self):
self.p = SeveralButtons(0,500,500)
buttons.append(self.p)
self._scene.addWidget(self.p)
def updateButtons(self,phrase):
for b in buttons:
if b != buttons[0]:
self._scene.addWidgets(b)
# ADD BUTTON WIDGET IN buttons ARRAY TO THE _scene OBJECT
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ui = UiWindow()
ui.show()
sys.exit(app.exec_())
As it is shown in here I am trying to update widgets in main window with button click but I get QGraphicsProxyWidget::setWidget: cannot embed widget 0x24ac1a93000; already embedded error.
How can I overcome this problem or what is the sane way to make this work? My main goal in this program is that every button group can create their children button group when clicked. Doing this with classes is way to go or should I stick to methods in main window class when creating recursive widgets?
Thanks in advance.
EDIT:
class SeveralButtons(QtWidgets.QWidget):
b1Signal = QtCore.pyqtSignal()
def __init__():
self.button1 = QtWidgets.QPushButton()
self.button1.clicked.connect(self.b1)
...
def b1(self):
sb = SeveralButtons()
buttons.append(sb)
self.b1Signal.emit()
class UiWindow(QtWidgets.QMainWindow):
def __init__():
...
self.sb1 = SeveralButtons()
buttons.append(sb1)
self._scene.addWidget(self.sb1)
self.sb1.b1Signal.connect(self.updateButtons)
def updateButtons():
for b in buttons:
if b != buttons[0]:
self._scene.addWidget(b)
The SeveralButtons class should not be responsible of creating new buttons outside itself.
You should emit that signal and connect it to the function of its parent, which will then create a new instance of the same class and also connect the signal.
class SeveralButtons(QtWidgets.QWidget):
b1Signal = QtCore.pyqtSignal()
def __init__():
super().__init__()
layout = QtWidgets.QHBoxLayout(self)
self.button1 = QtWidgets.QPushButton()
self.button1.clicked.connect(self.b1Signal)
layout.addWidget(self.button1)
class UiWindow(QtWidgets.QMainWindow):
def __init__():
# ...
self.buttons = []
self.addButtons()
def addButtons():
newButtons = SeveralButtons()
newButtons.b1Signal.connect(self.addButtons)
self.buttons.append(newButtons)
self._scene.addWidget(newButtons)

Python, Tkinter - root is not defined

I have a class - code below - which works flawlessly when called from if __name__ == '__main__': but when I call it from another .py file it spits an error. Apologies if this is a basic mistake on my part, but I tried a LOT of stuff and nothing seemed to work, would really love some help!
The error:
File "c:\Users\...\test.py", line 6, in <module>
app = Screenshot(root)
File "c:\Users\...\Screenshot.py", line 18, in __init__
self.master_screen = Toplevel(root)
NameError: name 'root' is not defined
The Class:
import time
from tkinter import Toplevel, Canvas, Frame, BOTH, YES, Tk
import pyautogui
import datetime
class Screenshot():
def __init__(self, master):
self.master = master
self.rect = None
self.x = self.y = 0
self.start_x = None
self.start_y = None
self.curX = None
self.curY = None
self.master_screen = Toplevel(root)
self.master_screen.title("Fenify")
self.master_screen.attributes("-transparent", "blue")
self.picture_frame = Frame(self.master_screen)
self.picture_frame.pack(fill=BOTH, expand=YES)
self.createScreenCanvas()
#TakeScreenshot
def takeBoundedScreenShot(self, x1, y1, x2, y2):
...
#Window
def createScreenCanvas(self):
...
#Controls
def on_button_press(self, event):
...
def on_button_release(self, event):
...
def on_right_click(self, event):
...
def on_move_press(self, event):
...
#Exit
def exit_screenshot(self):
...
if __name__ == '__main__':
root = Tk()
app = Screenshot(root)
root.mainloop()
example of calling from another class:
import tkinter
from Screenshot import Screenshot
root = tkinter.Tk()
app = Screenshot(root)
root.mainloop()
You want to set the parent/master of your Toplevel to self.master instead of root. root isn't defined in the scope of the Screenshot class, but the input argument master does point to it.
self.master_screen = Toplevel(self.master)

Is this 'self isnt defined' error a scope problem?

In my main script I have the following code:
class Sequence:
def __init__(self, colour, text):
self.colour = colour
self.width = 5
self.height = 5
self.text = text
def create_window(self, root):
self.name=tk.Label(root,text=self.text, wdith=self.width, height=self.height,
bg=self.colour
self.name.pack()
In my gui script this code is run as
Sequence.create_window(self, root)
I get the error:
Sequence.create_window(self, root) NameError: name 'self' is not defined
Im not really sure how to fix this, does it have do with the scope of the program?
You need to initialize an object first:
class Sequence:
def __init__(self, colour, text):
self.colour = colour
self.width = 5
self.height = 5
self.text = text
def create_window(self, root):
self.name=tk.Label(root,text=self.text, wdith=self.width, height=self.height,
bg=self.colour)
self.name.pack()
sequence = Sequence("blue", "test")
sequence.create_window(root)
root is a variable defined in create_window method
tk.Label need to be placed in either window or frame which is passed as first argument.
import sys
if sys.version_info.major == 2
# for python 2
import Tkinter as tk
else
# for python 3
import tkinter as tk
class Sequence:
def __init__(self, colour, text):
self.colour = colour
self.width = 5
self.height = 5
self.text = text
def create_window(self, root):
self.name=tk.Label(root, text=self.text, wdith=self.width, height=self.height,
bg=self.colour)
self.name.pack()
if __name__ == "__main__":
root = tk.Tk()
sequence = Sequence("blue", "test")
sequence.create_window(root)
root.mainloop()

Change value in OpenGLWidget from MainWindow (GUI)

Using python and bindings (pyqt, pyopengl) I have created a simple 3D viewer. I would like to create some basic actions operated/triggered by user interaction. The program has 2 parts.
opengl widget:
class OpenGLWidget(QtOpenGL.QGLWidget):
def __init__(self, parent=None):
self.parent = parent
QtOpenGL.QGLWidget.__init__(self, parent)
...
def draw(self):
#here I would like to change colour of background from right mouse click menu
glClearColor(self.R,self.G,self.B,1)
main widget:
class MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.resize(initial_window_width, initial_window_height)
self.setWindowTitle('Window Name')
self.setMouseTracking(True)
# location of window on screen
self.setGeometry(5, 25, initial_window_width, initial_window_height)
self.createActions()
self.createMenus()
# sets opengl window in central widget position
self.OpenGLWidget = OpenGLWidget()
self.setCentralWidget(self.OpenGLWidget)
#pyqtSlot(QtCore.QPoint)
def contextMenuRequested(self,point):
menu = QtGui.QMenu()
action1 = menu.addAction("Blue")
self.connect(action1,SIGNAL("triggered()"), self,SLOT("Blue()"))
menu.exec_(self.mapToGlobal(point))
#pyqtSlot()
def Blue(self):
self.R = 0
self.G = 0
self.B = 1
The code that runs the entire program:
if __name__=='__main__':
app = QtGui.QApplication(sys.argv)
win = MainWindow()
win.setContextMenuPolicy(QtCore.Qt.CustomContextMenu);
win.connect(win, SIGNAL("customContextMenuRequested(QPoint)"),
win, SLOT("contextMenuRequested(QPoint)"))
win.show()
sys.exit(app.exec_())
I would like to know how to change the values R, G, B in main widget that the background colour will change to blue in opengl widget.
Inside OpenGLWidget class add the following method:
def setColor(R, G, B):
self.R = R
self.G = G
self.B = B
Inside MainWindow in Blue() replace the existing code with the following one:
self.OpenGLWidget.setColor(0,0,1)
self.openGLWidget.draw() # or do whatever you want, variables are changed in `OpenGLWidget`
To set color to green, call setColor() with 0,1,0 parameters.

Animated Tkinter

I am trying to write a basic tkinter example that will show a box stretching across a frame. At this point the code below will only print the final result, and not show the box moving. How do I fix the code so that it will work over time with out using something like move, so that I can modify the shape over time later?
from tkinter import Tk, Canvas, Frame, BOTH
from time import sleep
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.parent.title("Board")
self.pack(fill=BOTH, expand=1)
self.canvas = Canvas(self)
self.ctr = 10
self.initUI()
def initUI(self):
print(self.ctr)
#The first four parameters are the x,y coordinates of the two bounding points.
#The top-left and the bottom-right.
r = self.canvas.create_rectangle((self.ctr * 10), 0, (self.ctr * 10 + 50), 50,
outline="#fb0", fill="#fb0")
'''
canvas.create_rectangle(50, 0, 100, 50,
outline="#f50", fill="#f50")
canvas.create_rectangle(100, 0, 150, 50,
outline="#05f", fill="#05f")
'''
self.canvas.pack(fill=BOTH, expand=1)
if self.ctr > 0:
self.updateUI()
def updateUI(self):
self.ctr -= 1
sleep(1)
self.initUI()
def main():
root = Tk()
root.geometry("400x100+300+300")
ex = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
This should get you partway there (you'll need to fix the indenting, the offsets are not correct and the counter doesn't get reset). In future, make sure you don't call sleep when you are using the event loop of a GUI for example. Most GUI's have a method to hook something into their event loops (the root.after call in this case). All I've done is make your code work partially - this should not be seen as indicative of idiomatic python.
from tkinter import Tk, Canvas, Frame, BOTH
from time import sleep
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.parent.title("Board")
self.pack(fill=BOTH, expand=1)
self.canvas = Canvas(self)
self.ctr = 10
def initUI(self):
print(self.ctr)
#The first four parameters are the x,y coordinates of the two bounding points.
#The top-left and the bottom-right.
r = self.canvas.create_rectangle((self.ctr * 10), 0, (self.ctr * 10 + 50), 50,
outline="#fb0", fill="#fb0")
'''
canvas.create_rectangle(50, 0, 100, 50,
outline="#f50", fill="#f50")
canvas.create_rectangle(100, 0, 150, 50,
outline="#05f", fill="#05f")
'''
self.canvas.pack(fill=BOTH, expand=1)
self.ctr += 1
if self.ctr > 0:
self.parent.after(1000, self.initUI)
def main():
root = Tk()
ex = Example(root)
root.geometry("400x100+300+300")
root.after(1000, ex.initUI)
root.mainloop()
if __name__ == '__main__':
main()

Categories