PYQT5 connect two QSpinBox - python-2.7

i want know how to connect two QSpinBox with condition when we change the value of one of them the second one changed
i tried this using Qt designer
self.spinA.valueChanged['int'].connect(self.spinB.setValue)
the value is always the same ; i tried to connect label to spinA and use its value to get new value for spinB but i don't know how to do the same to change spinA value based on spinB value
and sorry for my english ; i can explain better with my native language

Add action to the first spin box for every value changed in the spin box, inside the action change the value of second spin box according to the relation between the values, do same for the second spin box as well below is the sample code.
importing libraries
from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class Window(QMainWindow):
def __init__(self):
super().__init__()
# setting title
self.setWindowTitle("Python ")
# setting geometry
self.setGeometry(100, 100, 600, 400)
# calling method
self.UiComponents()
# showing all the widgets
self.show()
# method for widgets
def UiComponents(self):
# creating spin box
self.spin1 = QSpinBox(self)
# setting geometry to spin box
self.spin1.setGeometry(100, 100, 150, 40)
# setting prefix to spin
self.spin1.setPrefix("Width : ")
# add action to this spin box
self.spin1.valueChanged.connect(self.action_spin1)
# creating another spin box
self.spin2 = QSpinBox(self)
# setting geometry to spin box
self.spin2.setGeometry(300, 100, 150, 40)
# setting prefix to spin box
self.spin2.setPrefix("Height : ")
# add action to this spin box
self.spin2.valueChanged.connect(self.action_spin2)
# method called after editing finished
def action_spin1(self):
# getting current value of spin box
current = self.spin1.value()
self.spin2.setValue(current)
# method called after editing finished
def action_spin2(self):
# getting current value of spin box
current = self.spin2.value()
self.spin1.setValue(current)
create pyqt5 app
App = QApplication(sys.argv)
create the instance of our Window
window = Window()
start the app
sys.exit(App.exec())

Related

Tkinter: Text in Frame in Nootbook tab not painted

OS is Win7 64bit, Python is 2.7.16 64bit. I have a simple Tkinter GUI: Root containing a Notebook with two tabs. First tab contains a Frame which contains a Button. Second tab contains a Frame which contains a Text. The command bound to the Button spawns a thread with sets the content of the Text.
import Tkinter
import ttk
import threading
r = Tkinter.Tk()
n = ttk.Notebook(r)
n.pack(expand=1, fill="both")
control = ttk.Frame(n)
info = ttk.Frame(n)
tInfo = Tkinter.Text(info)
tInfo.pack(expand=1, fill="both")
n.add(control, text='Control')
n.add(info, text='Info')
infoMutex = threading.Lock()
def doGuiTest():
try:
infoMutex.acquire()
tInfo.config(state='normal')
tInfo.delete('1.0', Tkinter.END)
tInfo.insert(Tkinter.END, 'Test')
tInfo.config(state='disabled')
finally:
infoMutex.release()
def workerThread():
doGuiTest()
def execute():
worker=threading.Thread(target=workerThread)
worker.start()
bExecute=Tkinter.Button(control, text='Execute', command=execute)
bExecute.pack()
r.mainloop()
Expected result: The Text is reliably visible with the set content after the Button is clicked.
Actual result: The Text is only visible when the tab containing the Text has been manually brought to the foreground before the Button is clicked.
When I set the content of the Text directly from the Button's command everything works as expected. Sadly, in the real application I am working on the functionality triggered by the Button will be running for several minutes so using another thread is a must.
What am I missing to achieve a consistent behavior?

Tkinter - Multiple windows opening

Like the title says I'm having a problem with multiple windows being able to open. New window (same window) every time I click the button. I haven't been able to find an answer to this specific scenario. I've even tried disabling the button after opening window (which led to the problem of re-enabling).
Below is enough code to work with, you can see the problem by clicking the button a few times. I am hoping for a somewhat easy solution as I am fairly new to Tkinter. Also, the smaller window needs to resize (expand) with the main window, so I dont think a Toplevel window would work.
There may be others having this same problem, and thanks in advance!
Note: I'm using Python 2.7 (Tkinter)
#!/usr/bin/python
import os
import sys
import Tkinter as tk
from Tkinter import *
from ScrolledText import *
import tkFileDialog
import tkMessageBox
# Main
root = tk.Tk(className = "tex")
root.geometry("500x300")
root.title("tex")
tex = ScrolledText(root, padx=2, pady=2, undo=True, font=('Arial 11'))
def note_area():
btn_frame = Frame()
note = LabelFrame(tex, bd=1, relief='ridge')
tx = Text(note, width=18, relief='flat', padx=2, pady=2)
tx.insert('1.0', "Notes..")
tx.pack(side='top', fill=BOTH, expand=True)
note.pack(side='right', fill=Y)
btn_frame.pack(side='bottom', fill=Y)
# ToolBar Button (should only open one instance of note_area)
toolbar = Frame(root, bd=2, relief='groove')
b4 = Button(toolbar, text="Notes", width=4, command=note_area)
b4.pack(side=RIGHT, padx=4, pady=2)
toolbar.pack(side=TOP, fill=X)
tex.pack(fill="both", expand=True)
root.mainloop()
You just need make up a variable to keep track of if you have a note window open or not.
tex.notes_open = False
def note_area():
if tex.notes_open:
return # abort the function, notes already open
else:
tex.notes_open = True # set the flag for the next time
# rest of your code

python 2.7 using tkinter -all checkbox are being checked when click on one only

I'm using python 2.7 with Tkinter (new to Tkinter:))
I have UI with list of 20 checkboxes
once I click on one checkbox, all checkboxes are being checked, instead of one.
In code below you'll see 2 line (once with #)
with # -when click on checkbox only one is checked which is ok
without # -when click on one, all are being checked
The problem is that I want to know the status of each checkbox if checed or not and I have to define var=Intvar in order to "get" it status
Any suggestion?
Thanks in advance
Below is relevant def
def suites_checkbox_create(self):
ExcelWorkBook1 = open_workbook(config.UI_Suites_Location + 'STD_SUITES.xlsx', on_demand=True)
First_Sheet1 = ExcelWorkBook1.sheet_by_index(0)
plushight = 110
suitesList=[]
self.CheckboxList=[]
for name in (First_Sheet1._cell_values):
if name[3] == "General Name":
continue
else:
suitesList.append(name[3])
for index, name in enumerate(suitesList):
self.var=IntVar
#self.CheckboxList.append(Checkbutton(self.app, text=name)) # using this, i can check once checkbox a time
self.CheckboxList.append(Checkbutton(self.app, text=name, variable=self.var)) # with this, once i check once checkbox, all checkboxes(20) are bing checked
self.CheckboxList[index].place(y=plushight)
plushight += 20
The reason this happens is because you've given all of your Checkbutton widgets the same variable for their variable attribute.
Meaning that as soon as one of the Checkbutton widgets is ticked self.var is given a value of 1 which means that all of the Checkbutton widgets have a value of 1 which equates to them having been selected.
In short, whenever one is ticked it updates the value of all the other's because they have the same variable used to store their value.
See this in the example below:
from tkinter import *
root = Tk()
var = IntVar()
for i in range(10):
Checkbutton(root, text="Option "+str(i), variable = var).pack()
root.mainloop()
To resolve this you need to use a different variable for each Checkbutton, like the below:
from tkinter import *
root = Tk()
var = []
for i in range(10):
var.append(IntVar())
Checkbutton(root, text="Option "+str(i), variable = var[i]).pack()
root.mainloop()

Fill a drop down menu with serial ports and saving the choosed label and using it later with Tkinter

I'm trying to do a GUI with Tkinter (python 2.7) that finds what serial COM's are in use and then the user can choose one to communicate with, much like Arduino's IDE in "Tools -> Port". I have two main problems: 1º When I insert the COM ports in the drop down menu, no matter which label I choose, always returns the higher COM number one. I've got an idea why but still can't solve it. 2º I don't know how to save the chosen label and use it later.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
from Tkinter import *
import tkMessageBox
from serial import *
import serial
def find_ports(): #find all active COM's
active_ports = []
for number in range(10):
try:
verify = serial.Serial('COM'+str(number))
active_ports.append((number, verify.portstr))
verify.close()
except serial.SerialException:
pass
return active_ports
def chooseCom(index): #choose COM by clicking on a label
choosedPort = portMenu.entrycget(index, "label")
print choosedPort
pass
numPorts = find_ports()
root = Tk()
# -------------------------- Main Frames --------------------------
toolbar = Frame(root)
data = Frame(root)
# -------------------------- Menu --------------------------
menu = Menu()
root.config(menu = menu)
subMenu = Menu(menu, tearoff = 0)
menu.add_cascade(label="Ports", menu = subMenu)
portMenu = Menu(subMenu, tearoff = 0)
for i,item in enumerate(numPorts):
portMenu.add_command(label=str(item[-1]), command = lambda: chooseCom(i))
serialPort = someVAr # someVar => Store the choosed label
baudRate = 9600
ser = Serial(serialPort , baudRate, timeout=0, writeTimeout=0)
subMenu.add_cascade(label="Ports", menu = portMenu)
root.mainloop()
For the 1º problem, I think that is the 'i' variable that stays with a high number by the end of the 'for'. The following code works instead of the 'for' loop:
portMenu.add_command(label="COM1", command = lambda: chooseCom(0))
portMenu.add_command(label="COM2", command = lambda: chooseCom(1))
unfortunately it doesn't work for me because I'll run this in different computers and I can't garantee that the COM ports will be the same.
The second problem is that I want to save the chosen label in some variable (someVar) and use it later to configure my Serial connection in:
serialPort = someVAr # someVar => Store the choosed label
baudRate = 9600
ser = Serial(serialPort , baudRate, timeout=0, writeTimeout=0)
Thank you.
Use partial instead of lambda (it's only there for backward compatibility).
from functools import partial
portMenu.add_command(label=str(item[-1]), command=partial(chooseCom, i))
Also, it is good to get in the habit of not using single letters than can look like numbers, i, l, O.
I would Strongly Suggest that you learn classes before going any further as it eliminates a lot of problems. Use a data attribute to store it, so it is visible anywhere within the class http://www.diveintopython.net/object_oriented_framework/userdict.html#fileinfo.userdict.init.example
import sys
if sys.version_info[0] < 3:
import Tkinter as tk ## Python 2.x
else:
import tkinter as tk ## Python 3.x
class StoreEntry():
def __init__(self, root):
""" shows how to store something in a variable, in this case
something entered in an Entry, and then print the stored
value some time later, in this case when the Exit Button
is pressed
"""
self.root=root
self.entered="**" #default=nothing entered
tk.Label(root, text="Enter Something").grid(row=0, column=0)
self.entry_1 = tk.Entry(root, width=10, bg="lightblue")
self.entry_1.grid(row=0, column=1, sticky="W")
tk.Button(root, text="return text entered", bg="lightgreen",
command=self.print_entry).grid(row=2, column=0)
tk.Button(root, text="Exit", bg="orange",
command=self.exit_this).grid(row=3, column=0)
def exit_this(self):
print "last text entered was", self.entered
self.root.quit()
def print_entry(self):
## store in a data attribute
self.entered=self.entry_1.get()
print self.entered
root=tk.Tk()
SE=StoreEntry(root)
root.mainloop()

Dynamically change the shape of bokeh Figure

I am building a web app that will display images as part of a data analysis pipeline. For this, I need to dynamically change the width and height of a Figure object in bokeh.
With the following code, the shape of the Figure is changed, but the change only takes effect after I resize my browser window, even if the browser window resize is ever so small.
import bokeh.plotting
import bokeh.models
import bokeh.layouts
# set up the interface
fig1 = bokeh.plotting.figure()
button = bokeh.models.Button(label='scramble')
# define a callback and connect it
def callback():
fig1.width = int(fig1.width * .8)
button.on_click(callback)
# add everything to the document
bokeh.plotting.curdoc().add_root(bokeh.layouts.column(button, fig1))
Is there some update method which I need to run? I have read about "next tick callbacks" but I don't understand if that is relevant.
The above behavior occurs both with firefox and chromium on my gnome system.
The reason this is happening is because the layout is not getting updated. Although your code changes the figure's property value you have to recompute all values in the Document solver for an actual resize to happen.
Here is the line in BokehJS where the resize hook happens:
https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/document.coffee#L92
After resize is called at the document level, resize objects re-render:
https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/models/layouts/layout_dom.coffee#L61
The problem is that there's not currently, to the best of my knowledge, an exposed way to re-trigger the document resize event.
However you can do it client side. Here's working code using CustomJS:
test.py
from bokeh.io import show
from bokeh.layouts import column
from bokeh.models import Button, CustomJS
from bokeh.plotting import figure
fig = figure()
button = Button(label='scramble')
button.callback = CustomJS(args=dict(fig=fig), code="""
var old_width = fig.width;
var doc = fig.document;
fig.width = old_width * 0.8;
doc.resize();
""")
col = column(button, fig)
show(col)
This can be run with python test.py.
Note you could also do this with bokeh server replacing the last line show(col) with curdoc().add_root(col), but I didn't do that to emphasize that this is a client-side solution.
There is a way to dynamically resize bokeh charts with built in functionality. For example,
fig = plotting.figure(width=1200, height=900, title="Dynamic plot".format(chartType), sizing_mode='scale_width')
The key option being sizing_mode='scale_width'
The width and height commands serve as initial values. There are other options for sizing_mode so I would look into that.