I am trying to update a wx.ListCtrl from another class. This is driving me crazy, and I don't understand what exactly I'm doing wrong. The widget is created inside a wx.Frame like:
class DataTable(gridlib.GridTableBase):
def __init__(self, data):
gridlib.GridTableBase.__init__(self)
self.data = data
#Store the row and col length to see if table has changed in size
self._rows = self.GetNumberRows()
self._cols = self.GetNumberCols()
print(self._rows, self._cols)
self.odd=gridlib.GridCellAttr()
self.odd.SetBackgroundColour((217,217,217))
self.even=gridlib.GridCellAttr()
self.even.SetBackgroundColour((255,255,255))
def GetAttr(self, row, col, kind):
attr = [self.even, self.odd][row % 2]
attr.IncRef()
return attr
def GetNumberRows(self):
return len(self.data)
def GetNumberCols(self):
return len(self.data.columns) + 1
def IsEmptyCell(self, row, col):
return False
def GetValue(self, row, col):
if col == 0:
pass
# return None #self.data.index[row]
else:
return self.data.iloc[row, col-1]
def SetValue(self, row, col, value):
if col == 0:
pass
else:
self.data.iloc[row, col - 1] = value
def GetColLabelValue(self, col):
try:
if col == 0:
return ""
#return 'Index' if self.data.index.name is None else self.data.index.name
else:
return self.data.columns[col - 1] #[col-1]
except:
pass
class DataGrid(gridlib.Grid):
def __init__(self, parent, data): # data
gridlib.Grid.__init__(self, parent, - 1) #,colnames,-1 # data
self.table = DataTable(data)
self.SetTable(self.table, True)
self.Bind(wx.grid.EVT_GRID_CELL_CHANGED, self.onCellChanged)
def onCellChanged(self,event):
#Establish connection
self.connect_mysql()
#Update database
key_id = str("'") + self.GetCellValue(event.GetRow(),1) + str("'") #FOR TESTING. CHANGE TO 0 WHEN IMPORT IS FIXED
target_col = self.GetColLabelValue(event.GetCol())
key_col = self.GetColLabelValue(1) #FOR TESTING. CHANGE TO 0 WHEN IMPORT IS FIXED
nVal = str("'") + self.GetCellValue(event.GetRow(),event.GetCol()) + str("'")
sql_update = "UPDATE " + tbl + " SET " + target_col + " = " + nVal + " WHERE " + key_col + " = " + key_id + ""
try:
self.cursor.execute(sql_update)
stat = "UPDATE"
oVal = event.GetString()
action = "UPDATE"
msg = "Changed " + str("'") + oVal + str("'") + " to " + nVal + " for " + key_id + " in table: " + str("'") + tbl + str("'")
#self.updateStatus()
except:
stat = "ERROR"
msg = "ERROR: Failed to update SQL table. " + "'" + tbl + "'"
self.db_con.rollback()
#Update dataframe
#Log the change
#MainFrame.test_print(stat,msg)
#MainFrame.lc_change.Append(["1","2", "3" + "\n"])
#Close connection
self.close_connection()
class MainFrame(wx.Frame):
def __init__(self, parent, data): # (self, parent, data):
wx.Frame.__init__(self, parent, -1, "Varkey Foundation") #, size=(640,480))
#Create a panel
self.p = wx.Panel(self)
self.Maximize(True)
#Create blank dataframe
data = pd.DataFrame() #pd.DataFrame(np.random.randint(0,100,size=(200, 5)),columns=list('EFGHD')
#data.reset_index(drop=True, inplace=True)
self.data = DataTable(data)
self.nb = wx.Notebook(self.p)
self.p.SetBackgroundColour( wx.Colour( 0, 0, 0 ) ) # 38,38,38
self.nb.SetBackgroundColour(wx.Colour(58, 56, 56) )
#self.SetBackgroundColour( wx.Colour( 255, 255, 56 ) )
#create the page windows as children of the notebook
self.page1 = PageOne(self.nb)
self.page2 = PageTwo(self.nb)
self.page3 = PageThree(self.nb)
# add the pages to the notebook with the label to show on the tab
self.nb.AddPage(self.page1, "Data")
self.nb.AddPage(self.page2, "Analyze")
self.nb.AddPage(self.page3, "Change Log")
#Create the grid and continue layout
self.grid = DataGrid(self.page1, data)
#grid.SetReadOnly(5,5, True)
#CreateFonts
self.b_font = wx.Font(14,wx.ROMAN,wx.NORMAL,wx.BOLD, True)
self.lbl_font = wx.Font(14,wx.ROMAN,wx.NORMAL,wx.NORMAL, True)
self.cb_font = wx.Font(11,wx.SCRIPT,wx.ITALIC,wx.NORMAL, True)
self.h_font = wx.Font(18,wx.DECORATIVE,wx.ITALIC,wx.BOLD, True)
#Create Title bmp
ico = wx.Icon('varkey_bmp.bmp', wx.BITMAP_TYPE_ICO) #'varkey_frame.bmp'
self.SetIcon(ico)
#Page 1 sizers and widgets
self.title = wx.StaticText(self.page1,label="TITLE",style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE)
self.title.SetForegroundColour((255,255,255))
self.title.SetFont(self.h_font)
self.p1_sizer = wx.BoxSizer(wx.VERTICAL)
self.p1_sizer.Add(self.title,0,wx.EXPAND,5)
self.p1_sizer.Add(self.grid,3,wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM ,25)
#self.p1_sizer.Add(self.btn_new,-0,wx.ALIGN_CENTER,5)
self.page1.SetSizer(self.p1_sizer)
#Page 2 sizers and widgets
self.analyze_grid = gridlib.Grid(self.page2)
self.analyze_grid.CreateGrid(0, 10)
self.p2_sizer = wx.BoxSizer(wx.VERTICAL)
self.p2_sizer.Add(self.analyze_grid,1,wx.EXPAND)
self.page2.SetSizer(self.p2_sizer)
#Page 3 sizers and widgets
self.log_grid = gridlib.Grid(self.page3)
self.log_grid.CreateGrid(0, 9)
self.log_grid.EnableEditing(False)
self.p3_sizer = wx.BoxSizer(wx.VERTICAL)
self.p3_sizer.Add(self.log_grid,1,wx.EXPAND)
self.page3.SetSizer(self.p3_sizer)
#Create widgets for top sizer
#Insert Image
self.staticbitmap = wx.StaticBitmap(self.p)
self.staticbitmap.SetBitmap(wx.Bitmap('varkey_logo2.jpg'))
self
self.lbl_user = wx.StaticText(self.p,label="Username:")
self.lbl_password = wx.StaticText(self.p,label="Password:")
self.lbl_interaction = wx.StaticText(self.p,label="Interaction:")
self.lbl_table = wx.StaticText(self.p,label="Table:")
#SetForground colors
self.lbl_user.SetForegroundColour((255,255,255))
self.lbl_password.SetForegroundColour((255,255,255))
self.lbl_interaction.SetForegroundColour((255,255,255))
self.lbl_table.SetForegroundColour((255,255,255))
#Set Fonts
self.lbl_user.SetFont(self.lbl_font)
self.lbl_password.SetFont(self.lbl_font)
self.lbl_interaction.SetFont(self.lbl_font)
self.lbl_table.SetFont(self.lbl_font)
self.tc_user =wx.TextCtrl(self.p,value='cmccall95',size = (130,25))
self.tc_password =wx.TextCtrl(self.p,value='Achilles95', style=wx.TE_PASSWORD | wx.TE_PROCESS_ENTER,size = (130,25))
self.tc_password.Bind(wx.EVT_TEXT_ENTER,self.onLogin)
self.tc_user.SetFont(self.cb_font)
self.tc_password.SetFont(self.cb_font)
self.btn_login = wx.Button(self.p,label="Login", size=(105,30))
self.btn_login.SetBackgroundColour(wx.Colour(198, 89, 17))
self.btn_login.SetFont(self.b_font)
self.btn_login.Bind(wx.EVT_BUTTON, self.onLogin) #connect_mysql
self.btn_logout = wx.Button(self.p,label="Logout",size=(105,30))
self.btn_logout.SetBackgroundColour(wx.Colour(192,0,0))
self.btn_logout.SetFont(self.b_font)
#self.btn_logout.Bind(wx.EVT_BUTTON, self.onLogout)
self.combo_interaction = wx.ComboBox(self.p, size = (160,25),style = wx.CB_READONLY | wx.CB_SORT | wx.CB_SORT)
self.combo_interaction.Bind(wx.EVT_COMBOBOX, self.onComboInteraction)
self.combo_table = wx.ComboBox(self.p, size = (160,25),style = wx.CB_READONLY | wx.CB_SORT | wx.CB_SORT)
self.combo_table.Bind(wx.EVT_COMBOBOX, self.onHideCommands)
self.combo_interaction.SetFont(self.cb_font)
self.combo_table.SetFont(self.cb_font)
#self.combo_table.Bind(wx.EVT_COMBOBOX ,self.OnComboTable)
self.btn_load = wx.Button(self.p,label="Load Table", size=(105,30))
self.btn_load.SetBackgroundColour(wx.Colour(31, 216, 6))
self.btn_load.SetFont(self.b_font)
#self.btn_load.Bind(wx.EVT_BUTTON, self.onLoadData)
self.btn_load.Bind(wx.EVT_BUTTON, self.test_reload)
self.lc_change = wx.ListCtrl(self.p,-1,style = wx.TE_MULTILINE | wx.LC_REPORT | wx.LC_VRULES)
self.lc_change.InsertColumn(0,"User ID")
self.lc_change.InsertColumn(1,"Status")
self.lc_change.InsertColumn(2,"Description")
self.lc_change.InsertColumn(3,"Date/Time")
#Set column widths
self.lc_change.SetColumnWidth(0, 75)
self.lc_change.SetColumnWidth(1, 75)
self.lc_change.SetColumnWidth(2, 450)
self.lc_change.SetColumnWidth(3, 125)
#Add Row Button
#self.btn_new = wx.Button(self.page1,label="+", size = (35,25))
#self.btn_new.SetForegroundColour(wx.Colour(112,173,71))
#self.btn_new.SetFont(self.h_font)
#self.btn_new.Bind(wx.EVT_BUTTON, self.onInsertRecordBelow)
#Create Filler text
self.lbl_filler = wx.StaticText(self.p,label="",size = (125,20))
#Create FlexGridSizers(For top half)
self.left_fgs = wx.FlexGridSizer(3,4,25,15)
self.left_fgs.AddMany([(self.lbl_user,1,wx.ALIGN_LEFT | wx.LEFT,15),(self.tc_user,1,wx.EXPAND),(self.lbl_interaction,1,wx.ALIGN_RIGHT|wx.RIGHT, 10),(self.combo_interaction,1,wx.EXPAND),
(self.lbl_password,1,wx.ALIGN_LEFT| wx.LEFT,15),(self.tc_password,1,wx.EXPAND),(self.lbl_table,1,wx.ALIGN_RIGHT|wx.RIGHT, 10),(self.combo_table),
(self.btn_login,2,wx.EXPAND),(self.btn_logout,1,wx.EXPAND),(self.lbl_filler,1,wx.EXPAND),(self.btn_load,1)])
#Create Top Sizer
self.top_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.top_sizer.Add(self.left_fgs,proportion = 1, flag = wx.ALL|wx.EXPAND,border = 30)
self.top_sizer.Add(self.staticbitmap,2,wx.TOP | wx.RIGHT, border = 40) #30
self.top_sizer.Add(self.lc_change,2,wx.RIGHT|wx.EXPAND ,30)
#create Bottom Sizer
self.bottom_sizer = wx.BoxSizer(wx.VERTICAL)
self.bottom_sizer.Add(self.nb,proportion = 5, flag = wx.LEFT |wx.RIGHT | wx.EXPAND,border = 30)
self.mainsizer = wx.BoxSizer(wx.VERTICAL)
self.mainsizer.Add(self.top_sizer,proportion = 0, flag = wx.ALL|wx.EXPAND,border = 5)
self.mainsizer.Add(self.bottom_sizer,proportion = 1,flag = wx.ALL|wx.EXPAND,border = 5)
#self.mainsizer.Add(self.status_sizer,proportion =0,flag = wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL, border = 15)
self.p.SetSizerAndFit(self.mainsizer)
self.hideWidgets()
self.onHideCommands(self)
#### Some functions...
if __name__ == '__main__':
import sys
app = wx.App()
frame = MainFrame(None, sys.stdout) # (None, sys.stdout)
frame.Show(True)
app.MainLoop()
I have another grid class where have some bound events.
class DataGrid(gridlib.Grid):
def __init__(self, parent, data):
gridlib.Grid.__init__(self, parent, - 1) #,colnames,-1
self.table = DataTable(data)
self.SetTable(self.table, True)
self.Bind(gridlib.EVT_GRID_CELL_RIGHT_CLICK, self.OnCellRightClick)
self.Bind(wx.grid.EVT_GRID_CELL_CHANGED, self.onCellChanged)
def onCellChanged(self,event):
try:
stat = "UPDATE"
msg = "Changed " + str("'") + self.oVal + str("'") + " to " + self.nVal + " for " + self.key_id + " in table: " + str("'") + tbl + str("'")
except:
stat = "ERROR"
msg = "ERROR: Failed to update SQL table. " + "'" + tbl + "'"
#self.updateStatus()
#MainFrame.test_print(stat,msg)
#self.MainFrame.lc_change.Append(["1","2", "3" + "\n"])
I have tried passing it directly to a function.
MainFrame.test_print(stat,msg)
Which works to pass the variables. The problem is when using "self", I get an error.
Then I've tried accessing the list control directly:
self.MainFrame.lc_change.Append(["1","2", "3" + "\n"])
And:
MainFrame.lc_change.Append(["1","2", "3" + "\n"])
These 2 give me "type object 'xxx' has no attribute 'xxx'
Can anyone tell me what I'm doing wrong?
What you need to do is to be able to allow the DataGrid to have a reference to the wx.ListCtrl that MainFrame creates.
class MainFrame(wx.Frame):
def __init__(self, parent, data): # (self, parent, data):
wx.Frame.__init__(self, parent, -1, "Varkey Foundation") #, size=(640,480))
#Create a panel
self.p = wx.Panel(self)
#Create the ListCtrl here:
self.lc_change = wx.ListCtrl(self.p,-1,style = wx.TE_MULTILINE | wx.LC_REPORT | wx.LC_VRULES)
...
# Later when you create the DataGrid:
#Create the grid and continue layout
self.grid = DataGrid(self.page1, data, self.lc_change) # pass in the ListCtrl
...
class DataGrid(gridlib.Grid):
def __init__(self, parent, data, lc):
gridlib.Grid.__init__(self, parent, - 1) #,colnames,-1
self.lc = lc
...
def onCellChanged(self,event):
...
self.lc.Append(["1","2", "3" + "\n"]) # Now update the ListCtrl
I'm building an app to 'roll' multiple die of the same face, so if I need to roll 5 8 sided die I select 5 in the QComboBox under the label D8, then 5 QLineEdit widgets pop up with the values of the 5 'die rolls' displayed.
Currently I'm able to display the correct number of QLineEdit widgets after a number in the QComboBox is selected. The problem comes when I try to remove the die roll displays entirely or set the number of QLineEdit widgets to less than the first value set. Sometimes it works, never when I try to set the displays to 0, other times I'll throw a KeyError or RuntimeError.
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QGridLayout, QPushButton, QLineEdit, QLabel, QComboBox, QDialog, QApplication
class RollMultiDiePopup(QDialog):
def __init__(self, parent=None):
super(RollMultiDiePopup, self).__init__(parent)
#self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Additional Dies to roll')
self.setContentsMargins(5, 5, 5, 5)
self.comboDict = {"D4": 4, "D6": 6, "D8": 8, "D10": 10, "D12": 12, "D20": 20}
self.comboLblDict = {"# of D4s": 0, "# of D6s": 0, "# of D8s": 0, "# of D10s": 0, "# of D12s": 0, "# of D20s": 0}
self.layoutGrid = QGridLayout(self)
self.layoutGrid.setSpacing(10)
self.gridRow = 0
self.gridCol = 0
self.comboLbl = {}
self.comboBoxes = {}
self.addnlInputs = {}
self.generatecombolabels()
self.generatecomboboxes()
self.generaterollbuttons()
self.setLayout(self.layoutGrid)
self.adjustSize()
def generatecombolabels(self):
self.gridCol = 0
for key, val in self.comboLblDict.items():
self.gridCol = self.gridCol + 1
self.comboLbl[key] = QLabel(key, self)
self.layoutGrid.addWidget(self.comboLbl[key], 0, self.gridCol)
def generatecomboboxes(self):
self.gridCol = 0
for key, val in self.comboDict.items():
self.gridCol = self.gridCol + 1
self.comboBoxes[key] = QComboBox(self)
self.comboBoxes[key].addItems([str(x) for x in range(21)])
#self.comboBoxes[key].activated.connect(self.adddisplays)
self.layoutGrid.addWidget(self.comboBoxes[key], 1, self.gridCol)
def generaterollbuttons(self):
self.gridCol = 0
for key, val in self.comboDict.items():
self.gridCol = self.gridCol + 1
buttons = QPushButton("Roll " + key + "s", self)
buttons.setToolTip("Roll D" + str(self.comboDict[key]) + " (1 - " + str(self.comboDict[key]) + ")")
#buttons.clicked.connect(partial(self.rolldie, val))
buttons.clicked.connect(self.adddisplays)
self.layoutGrid.addWidget(buttons, 2, self.gridCol)
def rolldie(self):
pass
def adddisplays(self):
d4s = int(self.comboBoxes["D4"].currentText())
d6s = int(self.comboBoxes["D6"].currentText())
d8s = int(self.comboBoxes["D8"].currentText())
d10s = int(self.comboBoxes["D10"].currentText())
d12s = int(self.comboBoxes["D12"].currentText())
d20s = int(self.comboBoxes["D20"].currentText())
dies = {1: d4s, 2: d6s, 3: d8s, 4: d10s, 5: d12s, 6: d20s}
#if d4s == 0 or d6s == 0 or d8s == 0 or d10s == 0 or d12s == 0 or d20s == 0:
self.removeaddeddisplays()
if d4s > 0 or d6s > 0 or d8s > 0 or d10s > 0 or d12s > 0 or d20s > 0:
for keys, vals in dies.items():
self.gridRow = 3
for i in range(vals):
self.gridRow += 1
self.addnlInputs["addnlInput" + str(i + 1)] = QLineEdit(self)
self.addnlInputs["addnlInput" + str(i + 1)].setAlignment(Qt.AlignRight)
self.addnlInputs["addnlInput" + str(i + 1)].setText("")
self.addnlInputs["addnlInput" + str(i + 1)].setPlaceholderText("Die Roll #" + str(i + 1))
self.layoutGrid.addWidget(self.addnlInputs["addnlInput" + str(i + 1)], self.gridRow, keys)
def removeaddeddisplays(self):
try:
for i in range(3, 21):
self.layoutGrid.removeWidget(self.addnlInputs["addnlInput" + str(i + 1)])
self.addnlInputs["addnlInput" + str(i + 1)].deleteLater()
self.addnlInputs["addnlInput" + str(i + 1)] = None
self.adjustSize()
except KeyError:
print("1")
except RuntimeError:
print("2")
if __name__ == "__main__":
app = QApplication()
w = RollMultiDiePopup()
w.show()
app.exec_()
This is the code to initially generate the QComboBoxes and populate the list of #s.
self.gridCol = 0
for key, val in self.comboDict.items():
self.gridCol = self.gridCol + 1
self.comboBoxes[key] = QComboBox(self)
self.comboBoxes[key].addItems([str(x) for x in range(21)])
#self.comboBoxes[key].activated.connect(self.adddisplays)
self.layoutGrid.addWidget(self.comboBoxes[key], 1, self.gridCol)
This is the code that adds the displays when the button that corresponds with the D# label/Combo box
d4s = int(self.comboBoxes["D4"].currentText())
d6s = int(self.comboBoxes["D6"].currentText())
d8s = int(self.comboBoxes["D8"].currentText())
d10s = int(self.comboBoxes["D10"].currentText())
d12s = int(self.comboBoxes["D12"].currentText())
d20s = int(self.comboBoxes["D20"].currentText())
dies = {1: d4s, 2: d6s, 3: d8s, 4: d10s, 5: d12s, 6: d20s}
#if d4s == 0 or d6s == 0 or d8s == 0 or d10s == 0 or d12s == 0 or d20s == 0:
self.removeaddeddisplays()
if d4s > 0 or d6s > 0 or d8s > 0 or d10s > 0 or d12s > 0 or d20s > 0:
for keys, vals in dies.items():
self.gridRow = 3
for i in range(vals):
self.gridRow += 1
self.addnlInputs["addnlInput" + str(i + 1)] = QLineEdit(self)
self.addnlInputs["addnlInput" + str(i + 1)].setAlignment(Qt.AlignRight)
self.addnlInputs["addnlInput" + str(i + 1)].setText("")
self.addnlInputs["addnlInput" + str(i + 1)].setPlaceholderText("Die Roll #" + str(i + 1))
self.layoutGrid.addWidget(self.addnlInputs["addnlInput" + str(i + 1)], self.gridRow, keys)
Here's the removeaddeddisplays function
try:
for i in range(3, 21):
self.layoutGrid.removeWidget(self.addnlInputs["addnlInput" + str(i + 1)])
self.addnlInputs["addnlInput" + str(i + 1)].deleteLater()
self.addnlInputs["addnlInput" + str(i + 1)] = None
self.adjustSize()
except KeyError:
print("1")
except RuntimeError:
print("2")
I've tried several different ways to remove the widgets and wound up with different results, only removing every other display, everything, every third..etc. This has been the most consistent way so far that I've found.
I'm using python 3 and pyside 2, I'll worry about handling the die rolls after I get the displays working properly.
If you want to remove a widget from a layout you just have to use deleteLater but that does not mean that the references will be deleted if they are stored in a list. In my strategy I eliminate all the QLineEdits with deleteLater, I reset the list that stored it and I create the new QLineEdits.
from PySide2 import QtCore, QtWidgets
class RollMultiDiePopup(QtWidgets.QDialog):
def __init__(self, parent=None):
super(RollMultiDiePopup, self).__init__(parent)
self._data = {
"D4": 4,
"D6": 6,
"D8": 8,
"D10": 10,
"D12": 12,
"D20": 20
}
self._lineedits = [[] for _ in self._data]
self._comboboxes = []
grid_layout = QtWidgets.QGridLayout(self)
self.create_labels()
self.create_comboboxes()
self.create_buttons()
def create_labels(self):
row = 0
grid_layout = self.layout()
for i, k in enumerate(self._data.keys()):
label = QtWidgets.QLabel("# of {}s".format(k))
grid_layout.addWidget(label, row, i)
def create_comboboxes(self):
row = 1
grid_layout = self.layout()
for i in range(len(self._data)):
combo = QtWidgets.QComboBox()
combo.addItems([str(j) for j in range(21)])
self._comboboxes.append(combo)
grid_layout.addWidget(combo, row, i)
def create_buttons(self):
row = 2
grid_layout = self.layout()
for i, (k, v) in enumerate(self._data.items()):
button = QtWidgets.QPushButton("Roll {}s".format(k))
button.setToolTip("Roll {}(1 - {})".format(k, v))
button.clicked.connect(self.update_lineedits)
grid_layout.addWidget(button, row, i)
#QtCore.Slot()
def update_lineedits(self):
row = 3
grid_layout = self.layout()
for r in self._lineedits:
for le in r:
le.deleteLater()
self._lineedits = [[] for _ in self._data]
for i, (les,combo) in enumerate(zip(self._lineedits, self._comboboxes)):
v = int(combo.currentText())
for j in range(v):
le = QtWidgets.QLineEdit()
le.setPlaceholderText("Die Roll #{}".format(j+1))
grid_layout.addWidget(le, row+j, i)
les.append(le)
QtCore.QTimer.singleShot(0, self.adjust_size)
#QtCore.Slot()
def adjust_size(self):
animation = QtCore.QPropertyAnimation(self, b"size", self)
animation.setStartValue(self.size())
animation.setEndValue(self.minimumSizeHint())
animation.start(QtCore.QAbstractAnimation.DeleteWhenStopped)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = RollMultiDiePopup()
w.show()
sys.exit(app.exec_())
I have two working stream.
1 - receiving data from com port and sends signal.
def __packet_parser(self, *args):
while self.__thred_is_runing:
data = self.__connection.read_all()
if data != b'':
self.change_data.emit(self.__readline())
self.__callback(self.__readline())
2 - draw graph.
def set_value_by_plot_name(self, value, name='default'):
self.__plots[name].setData(np.append(self.__plots[name].getData()[1][1:], value))
def __test(self, value):
tmp = value.decode('windows-1252')
data = tmp.split('\t')
if len(data) == 10:
self.__gr.set_value_by_plot_name(int(data[1]))
def main(self):
self.__window = Window()
self.__gr = Graphics()
w = self.__gr.get_widget()
self.__window.add_widget(w)
connect = COMPortConnection('COM7', 38400)
connect.change_data.connect(self.__test)
connect.open()
self.__window.show()
few seconds everything works fine, and then ceases to be updated.
What problem?
Data is updated, picture is not.
I had a similar problem, i solved it by passing by an intermediate method i'm not sure why:
class GraphWindowController:
# init ...
def start_graph(self):
# ... process
self.view.run_graph(self.graph_nodes)
stream_signals_and_slots = []
my_steam_signal.connect(self.add_value_to_graph)
def add_value_to_graph(self, values):
self.view.update(values)
class GraphWindow(QtGui.QFrame, Ui_GraphWindow):
def __init__(self, parent=None):
"""Initializer."""
super(GraphWindow, self).__init__(parent)
self.setupUi(self)
self.connect_signals()
self.plot_widget = None
self.y_data = []
self.x_data = []
self.curve = []
self.display_range = None
self.velocity = None
self.values_to_display = None
self.count_value_to_display = 0
self.legend = None
self.build_gui()
# Doing stuff ...
def build_gui(self):
self.plot_widget = pg.PlotWidget()
layout = QtGui.QGridLayout()
self.PlotLayout.setLayout(layout)
layout.addWidget(self.plot_widget, 0,1)
def configure_graph(self, display_range, velocity):
self.display_range = display_range
self.velocity = velocity
self.plot_widget.setLabels(left='axis 1')
self.legend = pg.LegendItem((100, 60), offset=(70, 30))
self.legend.setParentItem(self.plot_widget.graphicsItem())
self.plot_widget.showGrid(True, True, 251)
self.plot_widget.showButtons()
self.plot_widget.setRange(rect=None, xRange=[0, self.display_range], yRange=[
1300, -300], padding=0.09, update=True, disableAutoRange=True)
def run_graph(self, values_to_display):
self.values_to_display = values_to_display
self.curve_number = len(self.values_to_display)
for i in range(self.curve_number):
self.y_data.append([])
colors_to_use = self.enumerate_colors(
self.curve_number)
# Blablabla doing stuff ...
def update(self, my_values):
value = my_values
for i in range(self.curve_number):
if len(self.y_data[i]) >= int((self.display_range * 1000) / self.velocity):
del self.y_data[i][0]
else:
my_var = len(self.x_data) * (self.velocity / 1000.0)
self.x_data.append(my_var)
self.y_data[i].append(int(value[i]))
my_data_to_display = list(
zip(self.x_data, self.y_data[i]))
my_array = np.array(my_data_to_display)
self.curve[i].setData(my_array)
I want to populate a SQLite database with a value from a slider widget. I can update a cell using the keyboard but I can't get it to work when the cell is populated from the slider. I am using a button to trigger the population and the write to the database but when I click it, I get a 'sqlite3.OperationError: near "0": syntax error. Here is my code:
import wx
import wx.grid as gridlib
import sqlite3
class Grid(gridlib.Grid):
def __init__(self, parent, db):
gridlib.Grid.__init__(self, parent)
self.CreateGrid(10,5)
for row in range(10):
rowNum = row + 1
self.SetRowLabelValue(row, "cue %s" %rowNum)
self.db = db
self.cur = self.db.con.cursor()
meta = self.cur.execute("SELECT * from CUES")
labels = []
for i in meta.description:
labels.append(i[0])
labels = labels[1:]
for i in range(len(labels)):
self.SetColLabelValue(i, labels[i])
all = self.cur.execute("SELECT * from CUES ORDER by DTindex")
for row in all:
row_num = row[0]
cells = row[1:]
for i in range(len(cells)):
if cells[i] != None and cells[i] != "null":
self.SetCellValue(row_num, i, str(cells[i]))
self.Bind(gridlib.EVT_GRID_CELL_CHANGED, self.CellContentsChanged)
def CellContentsChanged(self, event):
x = event.GetCol()
y = event.GetRow()
val = self.GetCellValue(y,x)
if val == "":
val = "null"
ColLabel = self.GetColLabelValue(x)
InsertCell = "UPDATE CUES SET %s = ? WHERE DTindex = %d"%(ColLabel,y)
self.cur.execute(InsertCell, [(val),])
self.db.con.commit()
self.SetCellValue(y, x, val)
class TestFrame(wx.Frame):
def __init__(self, parent, db):
wx.Frame.__init__(self, parent, -1, "Grid plus db", size = (800,600))
panel = wx.Panel(self, -1)
self.db = db
self.cur = self.db.con.cursor()
sizer = wx.GridBagSizer(vgap=10, hgap=10)
self.slide1 = wx.Slider(panel, -1, 0, 0, 255, size=(50,400),
style=wx.SL_VERTICAL|wx.SL_AUTOTICKS|wx.SL_LABELS|wx.SL_INVERSE)
self.slide1.SetTickFreq(10)
self.Bind(wx.EVT_SCROLL_CHANGED, self.onReport, self.slide1)
self.slide2 = wx.Slider(panel, -1, 0, 0, 255, size=(50,400),
style=wx.SL_VERTICAL|wx.SL_AUTOTICKS|wx.SL_LABELS|wx.SL_INVERSE)
self.slide2.SetTickFreq(10)
self.grid = Grid(panel,db)
self.display = wx.TextCtrl(panel, -1, size=(200,100), style=wx.TE_MULTILINE)
self.aBtn = wx.Button(panel, -1, "Grid")
self.Bind(wx.EVT_BUTTON, self.onPopulate, self.aBtn)
self.bBtn = wx.Button(panel, -1, "Database")
sizer.Add(self.slide1, pos=(0,0))
sizer.Add(self.slide2, pos=(0,1))
sizer.Add(self.grid, pos = (0,2))
sizer.Add(self.aBtn, pos=(1,0))
sizer.Add(self.display, pos=(1,1), span=(2,2))
sizer.Add(self.bBtn, pos=(2,0))
panel.SetSizer(sizer)
panel.Fit()
def onReport(self,event):
val = self.slide1.GetValue()
self.display.WriteText("Slide 1 value = %s\n"%val)
def onPopulate(self, event):
"""Work in Progress"""
val = str(self.slide1.GetValue()) + '\n'
#put a dlg here to get row col - place in SetCellValue(x,y,....
self.grid.SetCellValue(0,0, val) #gets it to the grid...Need to write it to the database
InsertCell = "UPDATE CUES SET %s = ? WHERE DTindex = %d"%(0,0)
self.cur.execute(InsertCell, [(val),])
self.db.con.commit()
class GetDatabase():
def __init__(self, f):
try:
file = open(f)
file.close()
except IOError:
self.exists = 0
else:
self.exists = 1
self.con = sqlite3.connect(f)
if __name__ == "__main__":
import sys
db = GetDatabase("data.db")
app = wx.App()
frame = TestFrame(None, db)
frame.Show(True)
app.MainLoop()
The database was created in DB Browser for SQLite:
CREATE TABLE CUES (
DTindex INTEGER,
A string,
B string,
C string,
D string,
E string,
PRIMARY KEY(DTindex)
);
I think that it's a simple error in this line:
InsertCell = "UPDATE CUES SET %s = ? WHERE DTindex = %d"%(0,0)
0 whilst a valid value for DTindex is a not a valid value for a column name, which would be A,B,C,D or E.
Without knowing exactly what you are attempting to achieve, the following will function.
InsertCell = "UPDATE CUES SET %s = ? WHERE DTindex = %d"%('A',0)
But only if you have a record with a DTindex of 0 (zero), where it replaces the value of the column A with the value from your slider