How to show a QDialog - qt

I need to show a find dialog after pressing Ctrl+F in QWidget, which contains a QTableView. The find dialog will search in the first column of the table to find the matches.
I can show the QMessageBox after pressing Ctrl+F with the following code:
class Widget(QWidget):
def __init__(self,md,parent=None):
QWidget.__init__(self,parent)
layout=QVBoxLayout(self)
# initially construct the visible table
tv = QTableView()
# uncomment this if the last column shall cover the rest
tv.horizontalHeader().setStretchLastSection(True)
tv.show()
# set black grid lines
self.setStyleSheet("gridline-color: rgb(39, 42, 49)")
# construct the Qt model belonging to the visible table
model = NvmQtModel(md)
tv.setModel(model)
tv.resizeRowsToContents()
tv.resizeColumnsToContents()
# set the shortcut ctrl+F for find in menu
shortcut = QShortcut(QKeySequence('Ctrl+f'), self)
shortcut.activated.connect(self.handleFind)
# delegate for decimal
delegate = NvmDelegate()
tv.setItemDelegate(delegate)
self.setGeometry(200,200,600,600) # adjust this later
layout.addWidget(tv)
# set window title
self.setWindowTitle("TITLE")
# find function: search in the first column of the table
def handleFind(self):
reply = QMessageBox.question(
self, 'Find', 'Find Dialog',
QMessageBox.Yes | QMessageBox.No)
if reply == QMessageBox.Yes:
print('Yes')
else:
print('No')
Then I changed the QMessageBox to a QDialog, but now it does not work. I would appreciate if you could tell me where I am not doing it correctly:
class Widget(QWidget):
def __init__(self,md,parent=None):
QWidget.__init__(self,parent)
layout=QVBoxLayout(self)
# initially construct the visible table
tv = QTableView()
# uncomment this if the last column shall cover the rest
tv.horizontalHeader().setStretchLastSection(True)
tv.show()
# set black grid lines
self.setStyleSheet("gridline-color: rgb(39, 42, 49)")
# construct the Qt model belonging to the visible table
model = NvmQtModel(md)
tv.setModel(model)
tv.resizeRowsToContents()
tv.resizeColumnsToContents()
# set the shortcut ctrl+F for find in menu
shortcut = QShortcut(QKeySequence('Ctrl+f'), self)
shortcut.activated.connect(self.handleFind)
# delegate for decimal
delegate = NvmDelegate()
tv.setItemDelegate(delegate)
self.setGeometry(200,200,600,600) # adjust this later
layout.addWidget(tv)
# set window title
self.setWindowTitle("TITLE")
# find function: search in the first column of the table
def handleFind(self):
findDialog = QDialog()
findLabel = QLabel("Find what", findDialog)
findField = QLineEdit(findDialog)
findButton = QPushButton("Find", findDialog)
closeButton = QPushButton("Close", findDialog)
findDialog.show()

If you want the Dialog be a modal Dialog, call findDialog.exec_():
from PyQt4.QtGui import *
def handleFind():
findDialog = QDialog()
#findDialog.setModal(True)
findLabel = QLabel("Find what", findDialog)
findField = QLineEdit(findDialog)
findButton = QPushButton("Find", findDialog)
closeButton = QPushButton("Close", findDialog)
#findDialog.show()
findDialog.exec_()
app = QApplication([])
b = QPushButton("click me")
b.clicked.connect(handleFind)
b.show()
app.exec_()

Related

Streamlit session state and button

Does anyone know how the code below could be changed so that the print only happens when the button “Run” is clicked? Now the print is performed every time “inp” is changed.
import streamlit as st
inp = st.number_input(“inp”, min_value=0, max_value=10, step=1, value=10)
if ‘click’ not in st.session_state:
st.session_state.click = False
def onClickFunction():
st.session_state.click = True
st.session_state.out = inp
runButton = st.button(“Run”,
on_click=onClickFunction())
if st.session_state.click:
st.write(“out”, st.session_state.out)
Solution: remove the “()” after the onClickFunction.

Kivy regarding binding multiple buttons to each individual function

Hi I am new to Kivy and just started programming. I have problem, I want to bind all the buttons i created in the for loops to the on_release for every single buttons. So that to make all buttons once click is able to go different screens. Below is my a small part of my code( I EDITED with more information)
#this are the pictures of the buttons
a = '_icons_/mcdonald2.png'
b = '_icons_/boostjuice.png'
c = '_icons_/duckrice.png'
d = '_icons_/subway_logo.png'
e = '_icons_/bakery.png'
f = '_icons_/mrbean.png'
#these are the names of the different screen
n1 = 'mcdonald_screen'
n2 = 'boost_screen'
n3 = 'duck_screen'
n4 = 'subway_screen'
n5 = 'bakery_screen'
n6 = 'mrbean_screen'
arraylist = [[a,n1],[b,n2],[c,n3],[d,n4],[e,n5],[f,n6]]
self.layout2 = GridLayout(rows=2, spacing = 50,size_hint = (0.95,0.5),
pos_hint = {"top":.65,"x":0},padding=(90,0,50,0))
for image in arraylist:
self.image_outlet = ImageButton(
size_hint=(1, 0.1),
source= image[0])
self.screen_name = image[1]
self.image_outlet[0].bind(on_release= ??) ## This part is the one
i want to change
according to the
different screen
self.layout2.add_widget(self.image_outlet)
self.add_widget(self.layout2)
GUI = Builder.load("_kivy_/trying.kv")
class TRYINGApp(App):
def build(self):
return GUI
def change_screen(self,screen_name):
screen_manager = self.root.ids['screen_manager']
screen_manager.current = screen_name
#kv file#
# all the varies kv file screen
#: include _kivy_/variestime_screen.kv
#: include _kivy_/homescreen.kv
#: include _kivy_/mcdonaldscreen.kv
#: include _kivy_/firstpage.kv
#: include _kivy_/mrbeanscreen.kv
#: include _kivy_/boostscreen.kv
#: include _kivy_/duckscreen.kv
#: include _kivy_/subwayscreen.kv
#: include _kivy_/bakeryscreen.kv
GridLayout:
cols:1
ScreenManager:
id : screen_manager
FirstPage:
name :"first_page"
id : first_page
VariesTimeScreen:
name: "variestime_screen"
id: variestime_screen
HomeScreen:
name : "home_screen"
id : home_screen
McDonaldScreen:
name : "mcdonald_screen"
id : mcdonald_screen
BoostScreen:
name : "boost_screen"
id : boost_screen
DuckScreen:
name: "duck_screen"
id: duck_screen
SubwayScreen:
name:"subway_screen"
id: subway_screen
BakeryScreen:
name: "bakery_screen"
id: bakery_screen
MrBeanScreen:
name: "mrbean_screen"
id : mrbean_screen
Your on_release can be something like:
self.image_outlet.bind(on_release=partial(self.change_screen, image[1]))
where change_screen is a method that you must define:
def change_screen(self, new_screen_name, button_instance):
# some code to change to the screen with name new_screen_name
Note that I have removed the [0] from self.image_outlet (I suspect that was a typo). I can't determine what code should go in the new method, because you haven't provided enough information.
If you have a change_screen method in your App class, you can use that directly by referencing it in your on_release as:
self.image_outlet.bind(on_release=partial(App.get_running_app().change_screen, image[1]))
You will need to make a minor change to your change_screen method to handle additional args:
def change_screen(self, screen_name, *args):
screen_manager = self.root.ids['screen_manager']
screen_manager.current = screen_name

How to validate a field depending on the value of another field in Enaml?

Let's say I have a form with 2 IntFields. How can I validate IntField B depending on the input in IntField A?
e.g. if A == 1, B can only be within 0-30; if A == 2, B can only be within 0-50; else B can be any other numbers
From all I can google, I can only find IntValidator which validates the field only without the ability to link to another field. No examples that I can find that shows how I can update the min/max values in the IntValidator, nor any custom Validator which can take the value of another field such that validation can change according to change of value in another field...
enamldef IntFieldsWindow( Window ):
Container:
Form:
padding=0
Label:
text = 'Field A'
IntField: fld_a:
value = 0
Label:
text = 'Field B'
IntField: fld_b:
value = 0
After some tests, it is actually possible to pass fld_a to a custom validator, then get the fld_a.value in the validate function, finally set the custom validator to fld_b. Not sure if it is the way to do such validation though.
One way is to break the data out into a model and have it validate the members using an observer that is called when either member changes.
Then make the IntField bind to the model value (using <<) and update the model value using a notification handler (::) that catches and reports validation errors.
For example:
from atom.api import Atom, Int, observe
from enaml.stdlib.fields import IntField
from enaml.widgets.api import Window, Container, Label, Form
class Model(Atom):
a = Int()
b = Int()
#observe('a', 'b')
def _validate(self, change):
# When a or b is changed validate the model state
a, b = self.a, self.b
if a == 1:
if b < 0 or b > 30:
raise ValueError("B is out of range")
elif a == 2:
if b < 0 or b > 50:
raise ValueError("B is out of range")
enamldef Main(Window):
attr model = Model()
Container:
Form:
padding=0
Label:
text = 'Field A'
IntField: fld_a:
value << model.a
value ::
error.text = ''
try:
model.a = change['value']
except ValueError as e:
error.text = str(e)
Label:
text = 'Field B'
IntField: fld_b:
value << model.b
value ::
error.text = ''
try:
model.b = change['value']
except ValueError as e:
error.text = str(e)
Label:
text << 'A:{} B:{}'.format(model.a, model.b)
Label: error:
pass
Notice the that the label outputting the model values never has an invalid state! The validator on the model will ensure this never happens.

wxpython wx.combobox save wx.StaticText view help me

import wx
import sqlite3
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
self.panel = wx.Panel(self)
self.text = wx.StaticText(self.panel)
self.conn = sqlite3.connect("test.db")
self.cursor = self.conn.cursor()
self.autoRefersh()
def autoRefersh(self):
self.LoadList()
wx.CallLater(1000, self.autoRefersh)
def LoadList(self):
self.cursor.execute("SELECT *FROM CLINIC1")
for date1 in self.cursor: pass
self.staticText2_1 = wx.StaticText(self.panel, label=date1[1], style=wx.ALIGN_CENTER, pos=(100,100))
if __name__ == '__main__':
app = wx.App()
frame = Frame()
frame.Show()
app.MainLoop()
combobox data sqlite3 save in why panel show Why it looks different bug??
I do not know why this is happening.
You missed one crucial step, getting the data itself.
You are using the cursor object not the data returned by the cursor.
def LoadList(self):
self.cursor.execute("SELECT *FROM CLINIC1")
data = self.cursor.fetchall()
for date1 in data: pass
self.staticText2_1 = wx.StaticText(self.panel, label=date1[1], style=wx.ALIGN_CENTER, pos=(100,100))
AS you are "passing" in your for loop perhaps what you actually want is only a single record, in which case
data = self.cursor.fetchone()
and drop the for loop
Even better, read the tutorial
https://www.blog.pythonlibrary.org/2012/07/18/python-a-simple-step-by-step-sqlite-tutorial/
In the heading of your question you mention combobox, so I assume that you want to replace the statictext with a combobox. The following should get you started, I'll leave the wx.EVT_COMBOBOX event binding for you to add, as you will need it to do something when you select an item.
import wx
import sqlite3
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
self.selected_data=[]
self.panel = wx.Panel(self)
self.combo = wx.ComboBox(self.panel,-1,choices=self.selected_data, size=(130,30))
self.conn = sqlite3.connect("test.db")
self.cursor = self.conn.cursor()
self.combo.SetValue("Choose an Item")
self.autoRefresh()
def autoRefresh(self):
self.LoadList()
def LoadList(self):
self.combo.Clear()
self.cursor.execute("SELECT * FROM CLINIC1")
data = self.cursor.fetchall()
for date1 in data:
self.selected_data.append(date1[1])
for i in self.selected_data:
self.combo.Append(i)
if __name__ == '__main__':
app = wx.App()
frame = Frame()
frame.Show()
app.MainLoop()
Edit:
It should look like this.

How do I set the color of a toggle button in wxpython?

I have a collection of button that I've created and need to change the color of the button when it's pressed. Currently it set the default colors (grey = inactive; light blue = active):
but I want to change the color of active to red.
Here's my button class:
class ButtonClass(wx.Panel):
def __init__(self, parent, name, id):
wx.Panel.__init__(self, parent)
self.name = name
self.taskid = id
self.button = wx.ToggleButton(self, 1, size=(50, 50))
self.button.SetLabel('Start')
self.mainSizer = wx.BoxSizer(wx.HORIZONTAL)
self.mainSizer.Add(self.button)
self.Bind(wx.EVT_TOGGLEBUTTON, self.toggledbutton, self.button)
# Where the buttons change state
def toggledbutton(self, event):
# Active State
if self.button.GetValue() == True:
self.button.SetLabel('Stop')
# Inactive State
if self.button.GetValue() == False:
self.button.SetLabel('Start')
I've tried using self.button.SetColour , self.button.SetBackgroundColour , self.button.SetForegroundColour all of which were not successful. Is there a way to accomplish this within wxpython?
It seems to be platform dependant. This worked for me in Ubuntu, but not in Windows.
self.ToggleButtonObj = wx.ToggleButton(self, -1, 'ButtonLabel')
self.ToggleButtonObj.Bind(wx.EVT_TOGGLEBUTTON, self.OnToggleClick)
def OnToggleClick(self,event):
if self.ToggleButtonObj.GetValue():
self.ToggleButtonObj.SetBackgroundColour('#color1')
else:
self.ToggleButtonObj.SetBackgroundColour('#color2')
Workaround:
self.Button = wx.Button(self, -1, 'ButtonLabel')
self.Button.Bind(wx.EVT_BUTTON, self.OnToggleClick)
self.ButtonValue = False
def OnToggleClick(self,event):
if not self.ButtonValue():
self.Button.SetBackgroundColour('#color1')
self.ButtonValue = True
else:
self.Button.SetBackgroundColour('#color2')
self.ButtonValue = False
SetBackgroundColour() worked for me using colour in RGB mode (like (255,255,255)) in Windows 7 with python 2.7.3.

Resources