Is it possible to change the color of a frame background or any other widget to transparent light blue or any other transparent color?
Yes there is a way. Unfortunately it only works for the entire window (The window and all of the child widgets).
Here is a little demo I wrote up a while ago which does what you want, among other things.
Transparent Window Demo :
import Tkinter as Tk, re
class TransparentWin (Tk.Tk) :
''' Transparent Tk Window Class '''
def __init__ (self) :
Tk.Tk.__init__(self)
self.Drag = Drag(self)
''' Sets focus to the window. '''
self.focus_force()
''' Removes the native window boarder. '''
self.overrideredirect(True)
''' Disables resizing of the widget. '''
self.resizable(False, False)
''' Places window above all other windows in the window stack. '''
self.wm_attributes("-topmost", True)
''' This changes the alpha value (How transparent the window should
be). It ranges from 0.0 (completely transparent) to 1.0
(completely opaque). '''
self.attributes("-alpha", 0.7)
''' The windows overall position on the screen '''
self.wm_geometry('+' + str(439) + '+' + str(172))
''' Changes the window's color. '''
bg = '#3e4134'
self.config(bg=bg)
self.Frame = Tk.Frame(self, bg=bg)
self.Frame.pack()
''' Exits the application when the window is right clicked. '''
self.Frame.bind('<Button-3>', self.exit)
''' Changes the window's size indirectly. '''
self.Frame.configure(width=162, height=100)
def exit (self, event) :
self.destroy()
def position (self) :
_filter = re.compile(r"(\d+)?x?(\d+)?([+-])(\d+)([+-])(\d+)")
pos = self.winfo_geometry()
filtered = _filter.search(pos)
self.X = int(filtered.group(4))
self.Y = int(filtered.group(6))
return self.X, self.Y
class Drag:
''' Makes a window dragable. '''
def __init__ (self, par, dissable=None, releasecmd=None) :
self.Par = par
self.Dissable = dissable
self.ReleaseCMD = releasecmd
self.Par.bind('<Button-1>', self.relative_position)
self.Par.bind('<ButtonRelease-1>', self.drag_unbind)
def relative_position (self, event) :
cx, cy = self.Par.winfo_pointerxy()
x, y = self.Par.position()
self.OriX = x
self.OriY = y
self.RelX = cx - x
self.RelY = cy - y
self.Par.bind('<Motion>', self.drag_wid)
def drag_wid (self, event) :
cx, cy = self.Par.winfo_pointerxy()
d = self.Dissable
if d == 'x' :
x = self.OriX
y = cy - self.RelY
elif d == 'y' :
x = cx - self.RelX
y = self.OriY
else:
x = cx - self.RelX
y = cy - self.RelY
if x < 0 :
x = 0
if y < 0 :
y = 0
self.Par.wm_geometry('+' + str(x) + '+' + str(y))
def drag_unbind (self, event) :
self.Par.unbind('<Motion>')
if self.ReleaseCMD != None :
self.ReleaseCMD()
def dissable (self) :
self.Par.unbind('<Button-1>')
self.Par.unbind('<ButtonRelease-1>')
self.Par.unbind('<Motion>')
def __run__ () :
TransparentWin().mainloop()
if __name__ == '__main__' :
__run__()
For what it's worth, here's an arguably more readable version of the code in #rectangletangle's answer that has been re-formatted to more closely adhere to PEP 8 - Style Guide for Python Code recommendations.
Except for a trivial modification to the way the Tkinter module is imported so it will work in both Python 2 and 3, all other executable code is identical to his.
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
import re
class TransparentWin(tk.Tk):
""" Transparent Tkinter Window Class. """
def __init__(self):
tk.Tk.__init__(self)
self.Drag = Drag(self)
# Sets focus to the window.
self.focus_force()
# Removes the native window boarder.
self.overrideredirect(True)
# Disables resizing of the widget.
self.resizable(False, False)
# Places window above all other windows in the window stack.
self.wm_attributes("-topmost", True)
# This changes the alpha value (How transparent the window should be).
# It ranges from 0.0 (completely transparent) to 1.0 (completely opaque).
self.attributes("-alpha", 0.7)
# The windows overall position on the screen
self.wm_geometry('+' + str(439) + '+' + str(172))
# Changes the window's color.
bg = '#3e4134'
self.config(bg=bg)
self.Frame = tk.Frame(self, bg=bg)
self.Frame.pack()
# Exits the application when the window is right clicked.
self.Frame.bind('<Button-3>', self.exit)
# Changes the window's size indirectly.
self.Frame.configure(width=162, height=100)
def exit(self, event):
self.destroy()
def position(self):
_filter = re.compile(r"(\d+)?x?(\d+)?([+-])(\d+)([+-])(\d+)")
pos = self.winfo_geometry()
filtered = _filter.search(pos)
self.X = int(filtered.group(4))
self.Y = int(filtered.group(6))
return self.X, self.Y
class Drag:
""" Makes a window draggable. """
def __init__(self, par, dissable=None, releasecmd=None):
self.Par = par
self.Dissable = dissable
self.ReleaseCMD = releasecmd
self.Par.bind('<Button-1>', self.relative_position)
self.Par.bind('<ButtonRelease-1>', self.drag_unbind)
def relative_position(self, event):
cx, cy = self.Par.winfo_pointerxy()
x, y = self.Par.position()
self.OriX = x
self.OriY = y
self.RelX = cx - x
self.RelY = cy - y
self.Par.bind('<Motion>', self.drag_wid)
def drag_wid(self, event):
cx, cy = self.Par.winfo_pointerxy()
d = self.Dissable
if d == 'x':
x = self.OriX
y = cy - self.RelY
elif d == 'y':
x = cx - self.RelX
y = self.OriY
else:
x = cx - self.RelX
y = cy - self.RelY
if x < 0:
x = 0
if y < 0:
y = 0
self.Par.wm_geometry('+' + str(x) + '+' + str(y))
def drag_unbind(self, event):
self.Par.unbind('<Motion>')
if self.ReleaseCMD != None:
self.ReleaseCMD()
def dissable(self):
self.Par.unbind('<Button-1>')
self.Par.unbind('<ButtonRelease-1>')
self.Par.unbind('<Motion>')
def __run__():
TransparentWin().mainloop()
if __name__ == '__main__':
__run__()
Related
I wrote some code using Tkinter in Python 3 that plots a graph in a canvas. I also made it such that when I move the mouse over the canvas the graph scrolls to the left.
The problem is that I want the graph to scroll when I press the space bar for example. But I don't want it to scroll 1 step each time I press the space bar but I want it to start scrolling indefinitely when I press it once and stop the scroll when I press it again. I want the space bar to be a play/pause key.
How can I accomplish this? I don't want to use matplotlib anywhere.
MY CODE AS IT IS NOW:
from tkinter import *
import numpy as np
# The function of the graph
def f(x):
return np.sin(x)+np.sin(3*x-1)+np.sin(0.5*(x+np.pi))+0.3*np.sin(10*x)
class GraphPlot():
def __init__(self, master):
self.master = master
# Data for the graph and steps to move to the right
self.data_x = np.linspace(0, 4*np.pi, 1000)
self.data_y = f(self.data_x)
self.step = 0.1
# A switch to delete to clear the canvas each iteration before plotting the next frame
self.gate = False
# Setting the Tkinter window and the canvas in place
self.ws = master.winfo_screenwidth()
self.hs = master.winfo_screenheight()
ww = self.ws*0.75
hw = self.hs*0.50
self.canvas = Canvas(self.master, width = ww, height = hw, bg = 'black')
self.canvas.grid()
self.master.update()
self.w = self.canvas.winfo_width()
self.h = self.canvas.winfo_height()
self.canvas.focus_set()
# Plot first frame
self.drawData(self.data_x, self.data_y)
# Plot next frames each time I press the space bar
self.canvas.bind('<KeyPress-space>', self.updateData)
def drawData(self, data_x, data_y):
'''This is my function to plot a grpah in a canvas
canvas without embedding any matplotlib figure'''
# Setting the axis limits
x_min, x_max = min(data_x), max(data_x)
y_min, y_max = min(data_y), max(data_y)
# Translating data to pixel positions inside the canvas
pixel_x = (data_x-x_min)*self.w/(x_max-x_min)
pixel_y = -(data_y-y_max)*self.h/(y_max-y_min)
points = []
for i in range(len(data_x)):
points.append(pixel_x[i])
points.append(pixel_y[i])
points = tuple(points)
# Deleting previous frame before plotting the next frame (except for the first frame)
if self.gate:
self.canvas.delete('curve')
else:
self.gate = True
# Plotting
self.canvas.create_line(points, fill = 'white', tag = 'curve')
def updateData(self, event):
# Changing data for the next frame
self.data_x += self.step
self.data_y = f(self.data_x)
# Plot new frame
self.drawData(self.data_x, self.data_y)
root = Tk()
GraphPlot(root)
root.mainloop()
I've tried some ideas. For example I used a new function, PlayPause(), with a while loop and a new switch, self.go, but this didn't work as expected.
CODE THAT I EXPECTED TO WORK BUT DIDN'T:
from tkinter import *
import numpy as np
def f(x):
return np.sin(x)+np.sin(3*x-1)+np.sin(0.5*(x+np.pi))+0.3*np.sin(10*x)
class GraphPlot():
def __init__(self, master):
self.master = master
self.data_x = np.linspace(0, 4*np.pi, 1000)
self.data_y = f(self.data_x)
self.step = 0.1
self.go = False # The new switch
self.gate = False
self.ws = master.winfo_screenwidth()
self.hs = master.winfo_screenheight()
ww = self.ws*0.75
hw = self.hs*0.50
self.canvas = Canvas(self.master, width = ww, height = hw, bg = 'black')
self.canvas.grid()
self.master.update()
self.w = self.canvas.winfo_width()
self.h = self.canvas.winfo_height()
self.canvas.focus_set()
self.drawData(self.data_x, self.data_y)
self.canvas.bind('<KeyPress-space>', self.PlayPause)
def drawData(self, data_x, data_y):
x_min, x_max = min(data_x), max(data_x)
y_min, y_max = min(data_y), max(data_y)
pixel_x = (data_x-x_min)*self.w/(x_max-x_min)
pixel_y = -(data_y-y_max)*self.h/(y_max-y_min)
points = []
for i in range(len(data_x)):
points.append(pixel_x[i])
points.append(pixel_y[i])
points = tuple(points)
if self.gate:
self.canvas.delete('curve')
else:
self.gate = True
self.canvas.create_line(points, fill = 'white', tag = 'curve')
def updateData(self):
self.data_x += self.step
self.data_y = f(self.data_x)
self.drawData(self.data_x, self.data_y)
def PlayPause(self, event):
if self.go:
self.go = False
else:
self.go = True
while self.go:
self.updateData()
root = Tk()
GraphPlot(root)
root.mainloop()
You could add a method to toggle_play_pause, and bind the space key to it. Upon space key press, this method toggles a boolean flag pause that when turned off allows the update to be called.
update will keep calling itself every 10/1000 of a second, until the space key is pressed again, and the pause flag set to True.
import tkinter as tk
import numpy as np
def f(x):
return np.sin(x)+np.sin(3*x-1)+np.sin(0.5*(x+np.pi))+0.3*np.sin(10*x)
class GraphPlot():
def __init__(self, master):
self.master = master
# Data for the graph and steps to move to the right
self.data_x = np.linspace(0, 4*np.pi, 1000)
self.data_y = f(self.data_x)
self.step = 0.1
# A switch to delete to clear the canvas each iteration before plotting the next frame
self.gate = False
# Setting the Tkinter window and the canvas in place
self.ws = master.winfo_screenwidth()
self.hs = master.winfo_screenheight()
ww = self.ws * 0.75
hw = self.hs * 0.50
self.canvas = tk.Canvas(self.master, width=ww, height=hw, bg='black')
self.canvas.grid()
self.master.update()
self.w = self.canvas.winfo_width()
self.h = self.canvas.winfo_height()
self.canvas.focus_set()
# Plot first frame
self.drawData(self.data_x, self.data_y)
# Plot next frames each time I press the space bar
self.canvas.bind('<KeyPress-space>', self.toggle_play_pause)
self.pause = True
self._update_call_handle = None
def drawData(self, data_x, data_y):
'''This is my function to plot a grpah in a canvas
canvas without embedding any matplotlib figure'''
# Setting the axis limits
x_min, x_max = min(data_x), max(data_x)
y_min, y_max = min(data_y), max(data_y)
# Translating data to pixel positions inside the canvas
pixel_x = (data_x-x_min)*self.w/(x_max-x_min)
pixel_y = -(data_y-y_max)*self.h/(y_max-y_min)
points = []
for i in range(len(data_x)):
points.append(pixel_x[i])
points.append(pixel_y[i])
points = tuple(points)
# Deleting previous frame before plotting the next frame (except for the first frame)
if self.gate:
self.canvas.delete('curve')
else:
self.gate = True
# Plotting
self.canvas.create_line(points, fill = 'white', tag = 'curve')
def toggle_play_pause(self, dummy_event):
self.pause = not self.pause
if not self.pause:
self.updateData()
def updateData(self):
# Changing data for the next frame
self.data_x += self.step
self.data_y = f(self.data_x)
# Plot new frame
self.drawData(self.data_x, self.data_y)
if not self.pause:
self._update_call_handle = root.after(10, self.updateData)
else:
root.after_cancel(self._update_call_handle)
self._update_call_handle = None
root = tk.Tk()
GraphPlot(root)
root.mainloop()
Hello I got a problem with using the Tkinter package on python. I want to create a window containing two major widgets of which one is a canvas that will later show a grid with cells. When initializing the canvas I use "create_rectangle" to fill the canvas with the desired objects. Also when clicking on a cell (for testing reasons) the canvas should change its color in the area of the rectangle. However when initialy displaying the window at first no objects can be seen (the expected result would be only white colored rectangles) and only when a Click on the canvas is performed the area changes its color as desired.
While looking through the internet I tried several variations of the order of the pack()- and create_rectangle()-methods. This is the code:
from tkinter import *
from tkinter.ttk import *
import cells
GRID_WIDTH = 15
GRID_HEIGHT = 15
class Ui(Frame):
""" Class to represent the ui of conways game of life"""
def __init__(self, parent, grid):
self.parent = parent
self.grid = grid
Frame.__init__(self, parent)
self.__setup()
def __setup(self):
""" Method to setup the components of the ui """
self.parent.title("Conway's game of life")
self.pack()
#Setup a frame to hold control components
frame_cntrl = Frame(self)
frame_cntrl.pack(side = RIGHT, anchor="n")
self.__setup_cntrl_components(frame_cntrl)
#Setup a frame to hold the Grid
self.canvas = Canvas(self)
self.canvas.pack(side = LEFT)
self.__draw_grid()
self.canvas.bind("<Button-1>", self.__canvas_clicked)
def __setup_cntrl_components(self, parent):
""" Method to setup the control elements of the ui"""
#Setup a label for the generation
self.lb_generation = Label(parent, text="dummy")
self.lb_generation.pack(side = TOP)
#Setup a button for iteration
self.bt_iteration = Button(parent, text="Iterate")
self.bt_iteration.pack(side = TOP)
def __draw_cell(self, x, y):
""" Draws a cell on the canvas"""
width, height = self.canvas.winfo_width(), self.canvas.winfo_height()
color = "black" if self.grid.cell_alive(x, y) else "white"
x0 = width * x / self.grid.width + 1
x1 = width * (x + 1) / self.grid.width
y0 = height * y / self.grid.height + 1
y1 = height * (y + 1) / self.grid.height
self.canvas.create_rectangle(x0, y0, x1, y1, width=0, fill=color)
def __draw_grid(self):
""" Method to setup the grid itself"""
width, height = self.canvas.winfo_width(), self.canvas.winfo_height()
for i in range(0, self.grid.width):
for j in range(0, self.grid.height):
self.__draw_cell(i, j)
def __canvas_clicked(self, event):
""" Method for when the cell was clicked """
x, y, width, height = event.x, event.y, self.canvas.winfo_width(), self.canvas.winfo_height()
cell_x = int(x / width * self.grid.width)
cell_y = int(y / height * self.grid.height)
self.grid.switch_cell(cell_x, cell_y)
self.__draw_cell(cell_x, cell_y)
if __name__ == "__main__":
Ui(Tk(), cells.Grid(GRID_WIDTH, GRID_HEIGHT)).mainloop()
Problem 1:
Your main problem is that, before the canvas is actually displayed, canvas.winfo_width() and canvas.winfo_height() do not return the canvas width and height, but the value 1.
I suggest you create the canvas as follows:
# Define canvas and save dimensions
self.canvas_width = 300
self.canvas_height = 200
self.canvas = Canvas(self, width = self.canvas_width,
height = self.canvas_height)
Then, in your code, replace each instance of:
width, height = self.canvas.winfo_width(), self.canvas.winfo_height()
with
width, height = self.canvas_width, self.canvas_height
Problem 2:
When creating each cell I don't think you need to add 1 to x0 and y0. Instead, it should be:
x0 = width * x / self.grid.width
x1 = width * (x + 1) / self.grid.width
y0 = height * y / self.grid.height
y1 = height * (y + 1) / self.grid.height
I used the code below which I found on internet to implement a mouse hovering action in python:
from tkinter import *
import numpy as np
class rect:
def __init__(self, root):
self.root = root
self.size = IntVar()
self.canvas = Canvas(self.root, width=800, height=300)
self.scale = Scale(self.root, orient=HORIZONTAL, from_=3, to=20, tickinterval=1, variable=self.size)
self.scale.bind('<ButtonRelease>', self.show)
self.canvas.bind('<Motion>', self.motion)
self.board = []
self.array = np.zeros((self.scale.get(),self.scale.get())).tolist()
self.canvas.pack()
self.scale.pack()
def motion(self,event):
if self.canvas.find_withtag(CURRENT):
current_color = self.canvas.itemcget(CURRENT, 'fill')
self.canvas.itemconfig(CURRENT, fill="cyan")
self.canvas.update_idletasks()
self.canvas.after(150)
self.canvas.itemconfig(CURRENT, fill=current_color)
def show(self,event):
self.canvas.delete('all')
x = 50
y = 50
row = []
self.board.clear()
for i in range(self.scale.get()):
row = []
for j in range(self.scale.get()):
rectangle = self.canvas.create_rectangle(x, y, x + 50, y + 50, fill='red')
x += 50
row.append(rectangle)
x -= j*50
y +=50
self.board.append(row)
print(self.board)
root = Tk()
a = rect(root)
root.mainloop()
The problem with the execution is that the color of the item changes to blue only for a limited time.
I need the color of each item in the canvas to be changed whenever I enter its zone and remain blue until the mouse is leaving the item.
You can pass the argument activefill when creating your rectangle.
From effboot.org:
Fill color to use when the mouse pointer is moved over the item, if
different from fill.
To do so, replace:
rectangle = self.canvas.create_rectangle(x, y, x + 50, y + 50, fill='red')
By:
rectangle = self.canvas.create_rectangle(x, y, x + 50, y + 50, fill='red', activefill='cyan')
This removes the need to bind Motion to your canvas, and also makes the code noticebly shorter:
from tkinter import *
import numpy as np
class rect:
def __init__(self, root):
self.root = root
self.size = IntVar()
self.canvas = Canvas(self.root, width=800, height=300)
self.scale = Scale(self.root, orient=HORIZONTAL, from_=3, to=20, tickinterval=1, variable=self.size)
self.scale.bind('<ButtonRelease>', self.show)
self.board = []
self.array = np.zeros((self.scale.get(),self.scale.get())).tolist()
self.canvas.pack()
self.scale.pack()
def show(self,event):
self.canvas.delete('all')
x = 50
y = 50
row = []
self.board.clear()
for i in range(self.scale.get()):
row = []
for j in range(self.scale.get()):
rectangle = self.canvas.create_rectangle(x, y, x + 50, y + 50, fill='red', activefill='cyan')
x += 50
row.append(rectangle)
x -= j*50
y +=50
self.board.append(row)
print(self.board)
root = Tk()
a = rect(root)
root.mainloop()
I changed motion method and added self.last = None to __init__ method:
from tkinter import *
import numpy as np
class rect:
def __init__(self, root):
self.root = root
self.size = IntVar()
self.canvas = Canvas(self.root, width=800, height=300)
self.scale = Scale(self.root, orient=HORIZONTAL, from_=3, to=20, tickinterval=1, variable=self.size)
self.scale.bind('<ButtonRelease>', self.show)
self.canvas.bind('<Motion>', self.motion)
self.board = []
self.array = np.zeros((self.scale.get(),self.scale.get())).tolist()
self.canvas.pack()
self.scale.pack()
self.last = None
def motion(self, event):
temp = self.canvas.find_withtag(CURRENT)
if temp == self.last:
self.canvas.itemconfig(CURRENT, fill="cyan")
self.canvas.update_idletasks()
else:
self.canvas.itemconfig(self.last, fill="red")
self.last = temp
def show(self,event):
self.canvas.delete('all')
x = 50
y = 50
row = []
self.board.clear()
for i in range(self.scale.get()):
row = []
for j in range(self.scale.get()):
rectangle = self.canvas.create_rectangle(x, y, x + 50, y + 50, fill='red')
x += 50
row.append(rectangle)
x -= j*50
y +=50
self.board.append(row)
print(self.board)
root = Tk()
a = rect(root)
root.mainloop()
I have been trying to make a button in a class with tkinter, but the button doesn't appear. The rest of the game is fine. I is just when i try to add a quit button in the game class it doesn't appear. I am using python 3.4.3 . I am make a game that you pop bubbles with a submarine. I have tried self.button_quit = tkinter.Button(window, text="Quit") and this is the class code:
class Game():
height = 500
width = 800
mid_x = width / 2
mid_y = height / 2
bonus_score = 700
bubble_chance = 10
gap = 100
time_limit = 30
speed = 0.01
def __init__(self):
self.score = 0
self.bonus = 0
self.window = tkinter.Tk()
self.window.title('Bubble Blaster')
self.canvas = tkinter.Canvas(self.window, width=self.width,
height=self.height, bg='darkblue')
self.end = time.time() + self.time_limit
Text(self.canvas,50,30,'TIME')
Text(self.canvas,150,30,'SCORE')
self.gui_score = Text(self.canvas,150,50)
self.gui_time = Text(self.canvas,50,50)
self.canvas.pack()
self.bubbles = list()
self.ship = Ship(self.canvas)
self.ship.move(self.mid_x, self.mid_y)
def coords_of(cid):
pos = c.coords(cid)
x = (pos[0] + pos[2]) / 2
y = (pos[1] + pos[3]) / 2
return x, y
def create_bubble(self):
x = self.width + self.gap
y = random.randint(0,self.height)
self.bubbles.append(Bubble(self.canvas,x,y))
def move_bubbles(self):
for bubble in self.bubbles:
bubble.move(-bubble.speed,0)
def destroy_bubble(self,bubble):
self.bubbles.remove(bubble)
bubble.destroy()
def clean_up_bubbles(self):
for bubble in self.bubbles:
if bubble.x < -self.gap:
self.destroy_bubble(bubble)
def buttons(self):
self.button1 = tkinter.Button(window, text="Quit")
self.button1.tkinter.pack()
def run(self):
while time.time() < self.end:
if random.randint(1, self.bubble_chance) == 1:
self.create_bubble()
self.move_bubbles()
self.clean_up_bubbles()
self.score += self.ship_bubble_collision()
if (int(self.score / self.bonus_score)) > self.bonus:
self.bonus += 1
self.end += self.time_limit
self.time_left = int(self.end - time.time())
self.update_gui()
self.window.update()
self.ship.step()
time.sleep(self.speed)
Text(self.canvas,self.mid_x, self.mid_y,'GAME OVER',
font=('Helvetica',30))
Text(self.canvas,self.mid_x, self.mid_y + 30,
'Score ' + str(self.score))
Text(self.canvas,self.mid_x, self.mid_y + 45,'Bonus Time ' +
str(self.bonus * self.time_limit))
input()
def distance(self,x1,y1,x2,y2):
return math.sqrt((x2-x1)**2+(y2-y1)**2)
def ship_bubble_collision(self):
points = 0
for bubble in self.bubbles:
distance = self.distance(self.ship.x,self.ship.y,\
bubble.x,bubble.y)
boundary = self.ship.radius + bubble.radius
if distance < boundary:
points += bubble.radius + bubble.speed
self.destroy_bubble(bubble)
return points
def update_gui(self):
self.gui_score.update(str(self.score))
self.gui_time.update(str(self.time_left))
if __name__ == '__main__':
Game().run()
Add
buttons()
Where you need it to be called. Buttons can't appear without being called!
If you need more info on def, click here.
Also for future questions, please elaborate on your question more. It is hard to tell exactly what you are asking.
I'm totally stuck with 2 problems:
1) i'm using QSlider to set some values (they're float ~0.5, so i'm using *1000). SingleStep and PageStep work fine for keyboard input and mouse wheel, ticks're all set... But when i'm using mouse to drag the slider - it ignores all those ticks, steps, etc, and i want it to move only from one tick to another.
self.ui.x_coord.setMaximum(l_d*1000)
self.ui.x_coord.setSingleStep(l_d/N*1000)
self.ui.x_coord.setTickInterval(l_d/N*1000)
self.ui.x_coord.setTickPosition(QtGui.QSlider.TicksBothSides)
self.ui.x_coord.setPageStep(l_d/N * 10000)
is something missing here in my code (maybe smth like setMouseStep)?
2) That QSlider's connected to a function
self.graph = BPlot(self.ui)
self.ui.x_coord.valueChanged.connect(self.setCoordLabelValue)
....
def setCoordLabelValue(self):
x = self.ui.x_coord.value()/1000
y = self.ui.y_coord.value()/1000
self.graph.setCoordText(x,y)
....
class BPlot(QtGui.QGraphicsView):
def __init__(self, ui, parent=None):
super(BPlot, self).__init__(parent)
self.scene = QtGui.QGraphicsScene()
self.ui = ui
self.coordText = QtGui.QGraphicsTextItem(None, self.scene)
self.coordText.setPlainText("123")
self.x_offset = 40
self.y_offset = 20
self.currentPoint = QtGui.QGraphicsRectItem(None, self.scene)
self.cph = 4
self.cpw = 4
def resizeEvent(self, event):
size = event.size()
def showEvent(self, event):
aw = self.viewport().width()
ah = self.viewport().height()
self.scene.setSceneRect(0,0,aw,ah)
self.setScene(self.scene)
self.axis_pen = QtGui.QPen(QtCore.Qt.DashDotLine)
self.scene.addLine(0, 3/4*ah, aw, 3/4*ah, self.axis_pen)
self.normal_pen = QtGui.QPen(QtCore.Qt.SolidLine)
self.scene.addLine(self.x_offset, 3/4*ah - self.y_offset, aw - self.x_offset, 3/4*ah - self.y_offset)
self.currentPoint.setRect(self.x_offset - self.cpw/2, 3/4*ah - self.y_offset - self.cph/2, self.cpw, self.cph)
def setCoordText(self, x, y):
self.coordText.setPlainText(str(x) + ":" + str(y))
the problem is that setCoordText func doesn't redraw coordText. If i'll use print(coordText.toPlainText()) - i'll get the right output, but on the screen there'll be still "123" from __init__
I already tried adding self.scene.update() to the end of setCoordText, with no luck.
Ugh... Solved. Logic, where're u, my dear friend???
def setCoordLabelValue(self):
x = self.ui.x_coord.value()/1000
y = self.ui.y_coord.value()/1000
self.graph.setCoordText(x,y)
self.graph.invalidateScene()
.......
def paintEvent(self, event):
painter = QtGui.QPainter(self.viewport())
# set color and width of line drawing pen
painter.setPen(QtGui.QPen(QtCore.Qt.black, 2))
# drawLine(x1, y1, x2, y2) from point (x1,y1) to (x2,y2)
# draw the baseline
painter.drawText(10,20,str(x_coord))
# set up color and width of the bars
width = 20
painter.setPen(QtGui.QPen(QtCore.Qt.red, width))
delta = width + 5
x = 30
painter.end()
self.viewport().update()