bind ComboBox to function - python-2.7

I have an option menu and i bound it to a function but i can't put scrollbar on it so i used ComboBox instead. But now the binding doesn't work
Cat_options = ['Select Category']
self.var = StringVar(self.ViewWM)
conn = sqlite3.connect(self.DatabaseName)
conn.text_factory = str
cursor = conn.cursor()
cursor.execute("SELECT Category FROM Websites_info WHERE LoginName LIKE ?" ,(self.LoginName,))
conn.commit()
a =''
for row in cursor.fetchall():
if a == row:
pass
else:
row = str(row)
row = row.replace("('","")
row = row.replace("',)","")
Cat_options.append(row)
a = row
self.var.set(Cat_options[0]) # initial value
Cat_ComboBox = ttk.Combobox(self.ViewWM, textvariable = self.var , values = Cat_options)
Cat_ComboBox.place(x=10,y =45 , width = 183)
Cat_ComboBox.bind('<<ComboBoxSelected>>', self.Cat_callback)
b1 = Button(self.ViewWM,text="aaaa",command=self.Cat_callback)
b1.place(x = 200,y=200)
self.ViewWM.mainloop()
def Cat_callback(self, event=None):
self.Selcted_Cat = self.var.get()
print self.Selcted_Cat
print 'hello'
My a button works fine but doesn't bind

Problem is upper B in <<ComboBoxSelected>>. It has to be <<ComboboxSelected>>
Full working example
from __future__ import print_function
try:
# Python 2
import Tkinter as tk
import ttk
except ImportError:
# Python 3
import tkinter as tk
from tkinter import ttk
# -------
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.var = tk.StringVar()
options = ["Alpha", "Beta", "etc.", "Omega"]
cb = ttk.Combobox(self, textvariable=self.var, values=options)
cb.pack()
cb.bind('<<ComboboxSelected>>', self.callback)
b1 = ttk.Button(self, text="OK", command=self.callback)
b1.pack()
def callback(self, event=None):
print('--- callback ---')
print('var.get():', self.var.get())
if event:
print('event.widget.get():', event.widget.get())
# -------
App().mainloop()

with using
Cat_ComboBox.bind('<<ComboboxSelected>>',
lambda event: self.Cat_callback())
every thing its working now
Cat_options = ['Select Category']
self.var = StringVar(self.ViewWM)
conn = sqlite3.connect(self.DatabaseName)
conn.text_factory = str
cursor = conn.cursor()
cursor.execute("SELECT Category FROM Websites_info WHERE LoginName LIKE ?" ,(self.LoginName,))
conn.commit()
a =''
for row in cursor.fetchall():
if a == row:
pass
else:
row = str(row)
row = row.replace("('","")
row = row.replace("',)","")
Cat_options.append(row)
a = row
self.var.set(Cat_options[0]) # initial value
Cat_ComboBox = ttk.Combobox(self.ViewWM, textvariable = self.var , values = Cat_options)
Cat_ComboBox.place(x=10,y =45 , width = 183)
Cat_ComboBox.bind('<<ComboboxSelected>>',
lambda event: self.Cat_callback()) #changing in code
b1 = Button(self.ViewWM,text="aaaa",command=self.Cat_callback)
b1.place(x = 200,y=200)
self.ViewWM.mainloop()
def Cat_callback(self, event=None):
self.Selcted_Cat = self.var.get()
print self.Selcted_Cat
print 'hello'

Related

How to get the selected item in matching items of the list view using with pyqt4

Here is my sample code.I am learning the list view methods,I already posted one question,but i have a small doubt in my program.In my program after "fliter" i am getting the matched items of the word in that i want to choose the selected item using the enter key but it is printing the first item after selecting..I don't want to print the first item of the matched list..can any one please help me.Thank you in advance.
given below is my code:
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Dialog(QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent=parent)
vLayout = QVBoxLayout(self)
hLayout = QHBoxLayout()
self.lineEdit = QLineEdit(self)
hLayout.addWidget(self.lineEdit)
self.filter = QPushButton("filter", self)
hLayout.addWidget(self.filter)
self.filter.clicked.connect(self.filterClicked)
self.list = QListView(self)
vLayout.addLayout(hLayout)
vLayout.addWidget(self.list)
self.model = QStandardItemModel(self.list)
codes = [
'windows',
'windows xp',
'windows7',
'hai',
'habit',
'hack',
'good'
]
for code in codes:
item = QStandardItem(code)
self.model.appendRow(item)
self.list.setModel(self.model)
shorcut=QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Return), self)
shorcut.activated.connect(self.on_enter_pressed)
#QtCore.pyqtSlot()
def on_enter_pressed(self):
if len(self.lineEdit.text())>0:
self.filterClicked()
def filterClicked(self):
filter_text = str(self.lineEdit.text()).lower()
for row in range(self.model.rowCount()):
if filter_text in str(self.model.item(row).text()).lower():
self.list.setRowHidden(row, False)
self.list.setFocus()
else:
self.list.setRowHidden(row, True)
ix = self.list.selectionModel().selectedIndexes()
#here if i mentioned self.list.selectionModel().currentIndex() means it is automatically printing the first item in List_View
# i dont want to print first item ...after slecting the item in list view i will press enter key then only i want to print the selected item name
print ix.data()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = Dialog()
w.show()
sys.exit(app.exec_())
finally i got this answer..thq eyllanesc sir,i refer all your previous answers related to list view..Thank you so much..
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Dialog(QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent=parent)
vLayout = QVBoxLayout(self)
hLayout = QHBoxLayout()
self.lineEdit = QLineEdit(self)
hLayout.addWidget(self.lineEdit)
self.filter = QPushButton("filter", self)
hLayout.addWidget(self.filter)
self.filter.clicked.connect(self.filterClicked)
self.list = QListView(self)
vLayout.addLayout(hLayout)
vLayout.addWidget(self.list)
self.model = QStandardItemModel(self.list)
codes = [
'windows',
'windows xp',
'windows7',
'hai',
'habit',
'hack',
'good'
]
for code in codes:
item = QStandardItem(code)
self.model.appendRow(item)
self.list.setModel(self.model)
shorcut=QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Return), self)
shorcut.activated.connect(self.on_enter_pressed)
#QtCore.pyqtSlot()
def on_enter_pressed(self):
if len(self.lineEdit.text())>0:
self.filterClicked()
def filterClicked(self):
filter_text = str(self.lineEdit.text()).lower()
for row in range(self.model.rowCount()):
if filter_text in str(self.model.item(row).text()).lower():
self.list.setRowHidden(row, False)
self.list.setFocus()
else:
self.list.setRowHidden(row, True)
indexes = self.list.selectionModel().selectedIndexes()
for index in indexes:
print index.data().toString()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = Dialog()
w.show()
sys.exit(app.exec_())

PyQt4 / QTableView: "RunTime Error" while performing Undo & Redo actions using QUndoStack class

I have written the code for Undo & Redo actions for QTableView by using QUndoStack class in PyQt4.
The Undo action works fine; but when I perform Redo action, I am getting "RuntimeError: maximum recursion depth exceeded while calling a Python object."
I have used QTableView's pressed & dataChanged signals to retrieve the texts from model.
Following is the code sample.
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtSql import *
import os
import sys
import random
# SQL Query:---------------------------------------------------------------------------------------------
def StudentQuery():
StudentQuery = QSqlQuery()
StudentQuery.exec_("DROP TABLE STUDENTS")
StudentQuery.exec_("""CREATE TABLE STUDENTS (
s1 REAL NULL,
s2 REAL NULL,
s3 REAL NULL)""")
Students = ("STD1", "STD2", "STD3")
StudentQuery.prepare("INSERT INTO STUDENTS (s1, s2, s3) VALUES (?, ?, ?)")
for Student in Students:
s1 = random.randint(0, 25)
s2 = random.randint(0, 25)
s3 = random.randint(0, 25)
StudentQuery.addBindValue(QVariant(s1))
StudentQuery.addBindValue(QVariant(s2))
StudentQuery.addBindValue(QVariant(s3))
StudentQuery.exec_()
QApplication.processEvents()
# Ui Dialog:------------------------------------------------------------------------------------------------
class Ui_Student(QDialog):
def __init__(self, parent=None):
super(Ui_Student, self).__init__(parent)
self.setFixedSize(340, 170)
self.setWindowTitle("STUDENT")
self.model = QSqlTableModel(self)
self.model.setTable("STUDENTS")
self.model.setEditStrategy(QSqlTableModel.OnManualSubmit)
self.model.select()
self.view = QTableView(self)
self.view.setGeometry(QRect(10, 10, 320, 120))
self.view.setSelectionBehavior(QAbstractItemView.SelectItems)
self.view.setFocusPolicy(Qt.StrongFocus)
self.view.setModel(self.model)
self.view.installEventFilter(self)
QSqlDatabase.database().commit()
# Button Box:---------------------------------------------------------------------------------------------------
self.buttonBox = QDialogButtonBox(self)
self.buttonBox.setGeometry(QRect(118, 127, 100, 45))
self.buttonBox.setOrientation(Qt.Horizontal)
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok)
# SIGNAL & SLOT: -----------------------------------------------------------------------------------------------
QObject.connect(self.buttonBox, SIGNAL("accepted()"), self.accept)
QObject.connect(self.buttonBox, SIGNAL("rejected()"), self.reject)
# Code For Undo/Redo:---------------------------------------------------------------------------------------------------
self.undoStack = QUndoStack(self)
self.undoStack.setUndoLimit(10)
self.L_Row = []
self.L_Column = []
self.L_Text0 = []
self.L_Text1 = []
self.view.pressed.connect(self.InitialText)
self.view.model().dataChanged.connect(self.FinalText)
def InitialText(self, signal):
self.Row = signal.row()
self.Column = signal.column()
Model = self.view.model()
self.Text0 = Model.data(Model.index(self.Row, self.Column), 0).toString()
self.L_Row.append(self.Row)
self.L_Column.append(self.Column)
self.L_Text0.append(self.Text0)
# print self.L_Text0
def FinalText(self):
View = self.view
Model = self.view.model()
self.Text1 = Model.data(Model.index(self.Row, self.Column), 0).toString()
self.L_Text1.append(self.Text1)
for i in range(len(self.L_Text0)):
if not (self.L_Text0[i] == self.L_Text1[i]):
command = CommandEdit(View, Model, self.L_Row[i], self.L_Column[i],
self.L_Text0[i], self.L_Text1[i], "ABC")
self.undoStack.push(command)
# ContextMenu:---------------------------------------------------------------------------------------------------
def contextMenuEvent(self, event):
menu = QMenu(self)
UndoAction = self.undoStack.createUndoAction(self)
UndoAction.setText("&Undo")
menu.addAction(UndoAction)
UndoAction.setShortcuts(QKeySequence.Undo)
self.connect(UndoAction, SIGNAL("triggered()"), self.undoStack.undo)
RedoAction = self.undoStack.createUndoAction(self)
RedoAction.setText("&Redo")
menu.addAction(RedoAction)
RedoAction.setShortcuts(QKeySequence.Redo)
self.connect(RedoAction, SIGNAL("triggered()"), self.undoStack.redo)
menu.exec_(event.globalPos())
# QUndoCommand Class:---------------------------------------------------------------------------------------------------
class CommandEdit(QUndoCommand):
def __init__(self, View, Model, RowIndex, ColumnIndex, Text0, Text1, description):
super(CommandEdit, self).__init__(description)
self.view = View
self.model = Model
self.rowIndex = RowIndex
self.columnIndex = ColumnIndex
self.text0 = Text0
self.text1 = Text1
def undo(self):
self.model.setData(self.model.index(self.rowIndex, self.columnIndex), QVariant(self.text0))
def redo(self): # Error occurred while executing this function.
self.model.setData(self.model.index(self.rowIndex, self.columnIndex), QVariant(self.text1))
# Code Execute:---------------------------------------------------------------------------------------------------
if __name__ == "__main__":
app = QApplication(sys.argv)
filename = os.path.join(os.path.dirname(__file__), "STD.db")
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName(filename)
db.open()
StudentQuery()
form = Ui_Student()
form.show()
sys.exit(app.exec_())
Am I doing something wrong while defining def InitialText & def FinalText?

Update label of Menubutton Checkbuttons in Tkinter

I would like to update the label text of checkbuttons within a menubutton using an update function when a checkbutton is clicked.
I have got around it so far by deleting the whole menubutton and recreating but it doesn't work perfectly and adds unnecessary complexity. Here is what I have so far:
from Tkinter import *
INGREDIENTS = ['cheese','ham','pickle','mustard','lettuce']
def print_ingredients(*args):
values = [(ingredient, var.get()) for ingredient, var in data.items()]
print values
results = []
def update():
values = [(ingredient, var.get()) for ingredient, var in data.items()]
for value in values:
if value[1] == 1:
results.append(value[0])
print results
for value in values:
mb.menu.delete(0)
for ingredient in INGREDIENTS:
if ingredient in results:
on_val = 0
off_val = 1
click = "Clicked!"
else:
on_val = 1
off_val = 0
click = ""
var = IntVar()
mb.menu.add_checkbutton(label=ingredient + " " + click, variable=var, onvalue = on_val, offvalue = off_val, command = update)
data[ingredient] = var # add IntVar to the dictionary
data = {} # dictionary to store all the IntVars
top = Tk()
mb= Menubutton ( top, text="Ingredients", relief=RAISED )
mb.menu = Menu ( mb, tearoff = 0 )
mb["menu"] = mb.menu
for ingredient in INGREDIENTS:
var = IntVar()
mb.menu.add_checkbutton(label=ingredient, variable=var, command = update)
data[ingredient] = var # add IntVar to the dictionary
btn = Button(top, text="Print", command=print_ingredients)
btn.pack()
mb.pack()
top.mainloop()
Is there a way to update the label text of a checkbutton within a menubutton?
You could trace the variables you attached to the checkbuttons. If you name the variables after the ingredients and store them in a dict, you can get the ingredient and the variable in the callback of the trace and change the entry at the right index:
from Tkinter import *
INGREDIENTS = ['cheese','ham','pickle','mustard','lettuce']
def update(var_name, *args):
# Beacause we defined names for the BooleanVars, the first argument is the name of the changed Var
# We named the Vars after the ingredients
ingredient = var_name
# Get the actual var from the dict
var = data[var_name]
# Get the index of the clicked ingredient
i = INGREDIENTS.index(ingredient)
# Check wether the checkbutton is clicked on or not
if var.get() == True:
# If checked, change label to include 'Clicked'
mb.menu.entryconfigure(i, label = ingredient + ' Clicked!')
else:
# If unchecked, change label to just ingredient
mb.menu.entryconfigure(i, label = ingredient)
data = {} # dictionary to store all the IntVars
top = Tk()
mb= Menubutton ( top, text="Ingredients", relief=RAISED )
mb.menu = Menu ( mb, tearoff = 0 )
mb["menu"] = mb.menu
for ingredient in INGREDIENTS:
# Create a Boolean variable with the name of the ingredient
var = BooleanVar(name = ingredient)
# Trace changes to the variable
var.trace("w", update)
# Create Checkbutton without command
mb.menu.add_checkbutton(label=ingredient, variable=var)
# Add variable to the dictionary
data[ingredient] = var
mb.pack()
top.mainloop()

Select the table row (only one row) and edit the content in cells

With my code below, you can add/select the whole row and when edit button pressed, that print the current row on the screen.
Furthermore, previously all the rows are disabled! Instead of print the current row, I'll be able to edit the row when selected.
# -*- coding: utf-8 -*-
import sqlite3 as sql
from PyQt4 import QtCore, QtGui
import sys, os
class MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.tabs = QtGui.QTabWidget(self)
self.general = QtGui.QWidget()
self.tabs.addTab(self.general, "General")
cWidget = QtGui.QWidget(self)
self.setCentralWidget(cWidget)
self.general_table = QtGui.QTableWidget(self.general)
self.setHeader()
add_record = QtGui.QPushButton("Add Record")
edit = QtGui.QPushButton("Edit")
layout = QtGui.QVBoxLayout(cWidget)
layout.addWidget(self.tabs)
layout.addWidget(add_record)
layout.addWidget(edit)
self.connect(add_record, QtCore.SIGNAL('clicked()'), self.addRecord)
self.connect(edit, QtCore.SIGNAL('clicked()'), self.edit)
self.general_table.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
def addRecord(self):
rcount_general = self.general_table.rowCount()
self.general_table.insertRow(rcount_general)
def edit(self):
indexes = self.general_table.selectionModel().selectedRows()
for index in sorted(indexes):
print("Row %d is selected" % index.row())
def setHeader(self):
# General
self.general_table.setRowCount(1)
self.general_table.setColumnCount(3)
self.general_table.setHorizontalHeaderLabels(["A1", "A2", "A3"])
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
You could call the setFlags function on the item.
For editable:
item = QtGui.QTableWidgetItem()
item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled )
self.your_table.setItem(row, column, item)
For not editable:
item = QtGui.QTableWidgetItem()
item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable |
QtCore.Qt.ItemIsEnabled)
self.your_table.setItem(row, column, item)

Not able to Dynamical Update Kivy Label Text

I am trying to add rows to a table like GUI.
These rows are to be a list of labels.
Each row that is updated has the following methods in that class:
AddRow - To add the list of strings that will be the text in that
label.
AddLabel - Adds a label to that row and appends the Label list
AddLabelRow - Creates the list Row in the actual table and
initializes the text to "empty"
ChangeLableText - Takes an input list of strings and changes the string in the label for that class.
I then have initialized a list of objects ContentList[] for this class and call the methods
But no matter which object's ChangeLabelText is called, only the text for ContentList[0] is updated.
import json
import requests
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.lang import Builder
from kivy.uix.scrollview import ScrollView
from kivy.core.window import Window
from kivy.uix.button import Button
from kivy.app import runTouchApp
class AddContent(GridLayout):
#response = requests.get("http://localhost:10010/")
# Get the response data as a python object. Verify that it's a dictionary.
#data = response.json()[3]
#Column_keys = ["country", "date", "answered_calls", "total_calls", "asr", "mou", "aou"]
RowList = []
Label_List = []
size = 0
def AddRow(self, InputList):
self.RowList = InputList
self.size = len(InputList)
def AddLabel(self,LayoutObj):
lbl = Label(size_hint_y = None, height = 30)
LayoutObj.add_widget(lbl)
return lbl
def AddLabelRow(self,LayoutObj):
for i in range(self.size):
Lbl = self.AddLabel(LayoutObj)
Lbl.text = "empty"
#self.Label_List[i].text = data[Column_keys[i]]
#Lbl.text = str(self.data[self.Column_keys[i]])
self.Label_List.append(Lbl)
def ChangeLabel_ListText(self, TextList):
for i in range(self.size):
#self.Label_List[i].text = data[Column_keys[i]] #data is fetched from Db
self.Label_List[i].text = TextList[i]
class TableView(GridLayout):
Col_Names = ["Date","Vendor","Country","MOU","ASR","AOU"]
ContentList = [AddContent(),AddContent(),AddContent()]
def __init__(self,**kwargs):
self.layout = GridLayout(cols = len(self.Col_Names), padding =5)
self.layout.bind(minimum_height=self.layout.setter('height'))
for i in range(len(self.Col_Names)):
btn = Button(text=self.Col_Names[i], size_hint_y=None, height=30)
self.layout.add_widget(btn)
self.ContentList[0].AddRow(['1sample1','1sample2','1sample3','1sample4','1sample5','1sample6'])
self.ContentList[1].AddRow(['2sample1','2sample2','2sample3','2sample4','2sample5','2sample6'])
self.ContentList[2].AddRow(['3sample1','3sample2','3sample3','3sample4','3sample5','3sample6'])
for i in range(3):
self.ContentList[i].AddLabelRow(self.layout)
self.ContentList[2].ChangeLabel_ListText(['a','b','c','d','e','f'])
if __name__ == '__main__':
Table = TableView()
runTouchApp(Table.layout)
The line self.ContentList[2].ChangeLabel_ListText(['a','b','c','d','e','f'])
updates only the first row whatever number is given for the index.
I have been breaking my head over this for the past week. I had initially done this with only one class instead of two which gave the same output.
Any help will help greatly. Thanks!
Your first problem is that RowList, Label_List, and size are class attributes in your code. But you want to set them in every instance individually. Solution: initialize these attributes inside the __init__ method like this:
def __init__(self, **kwargs):
super(AddContent, self).__init__(**kwargs)
self.RowList = []
self.Label_List = []
self.size = 0
The second problem is, that the GridLayout (which your class is subclassing) also contains an attribute called size. Solution: pick a different name for this attribute like so:
self.length = 0
If you now do
self.ContentList[i].ChangeLabel_ListText(['a','b','c','d','e','f'])
your i-th ContentList-entry will be changed.
Here is the complete solution:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.lang import Builder
from kivy.uix.scrollview import ScrollView
from kivy.core.window import Window
from kivy.uix.button import Button
from kivy.app import runTouchApp
class AddContent(GridLayout):
#response = requests.get("http://localhost:10010/")
# Get the response data as a python object. Verify that it's a dictionary.
#data = response.json()[3]
#Column_keys = ["country", "date", "answered_calls", "total_calls", "asr", "mou", "aou"]
def __init__(self, **kwargs):
super(AddContent, self).__init__(**kwargs)
self.RowList = []
self.Label_List = []
self.length = 0
def AddRow(self, InputList):
self.RowList = InputList
self.length = len(InputList)
def AddLabel(self,LayoutObj):
lbl = Label(size_hint_y=None, height=30)
LayoutObj.add_widget(lbl)
return lbl
def AddLabelRow(self,LayoutObj):
for i in range(self.length):
Lbl = self.AddLabel(LayoutObj)
Lbl.text = "empty"
#self.Label_List[i].text = data[Column_keys[i]]
#Lbl.text = str(self.data[self.Column_keys[i]])
self.Label_List.append(Lbl)
def ChangeLabel_ListText(self, TextList):
for i in range(self.length):
#self.Label_List[i].text = data[Column_keys[i]] #data is fetched from Db
self.Label_List[i].text = TextList[i]
class TableView(GridLayout):
Col_Names = ["Date","Vendor","Country","MOU","ASR","AOU"]
ContentList = [AddContent(),AddContent(),AddContent()]
def __init__(self,**kwargs):
self.layout = GridLayout(cols = len(self.Col_Names), padding=5)
self.layout.bind(minimum_height=self.layout.setter('height'))
for i in range(len(self.Col_Names)):
btn = Button(text=self.Col_Names[i], size_hint_y=None, height=30)
self.layout.add_widget(btn)
self.ContentList[0].AddRow(['1sample1','1sample2','1sample3','1sample4','1sample5','1sample6'])
self.ContentList[1].AddRow(['2sample1','2sample2','2sample3','2sample4','2sample5','2sample6'])
self.ContentList[2].AddRow(['3sample1','3sample2','3sample3','3sample4','3sample5','3sample6'])
for i in range(3):
self.ContentList[i].AddLabelRow(self.layout)
self.ContentList[2].ChangeLabel_ListText(['a','b','c','d','e','f'])
if __name__ == '__main__':
Table = TableView()
runTouchApp(Table.layout)