I am trying to save a text file from the first page of a flatNotebook, write them to an EXTERNALLY defined sqLite database and write the values to a grid on the second page of the flatNotebook. The values are saved to the text file and written to the database successfully but I cannot get the values to populate the grid at the same time. They values show up in the grid after I close the program and restart it. I am having a hard time understanding how to call the function onAddCue(). I have tried so many things that I'm just confusing myself at this point. Please help me understand what I am doing wrong. Here is my entire code:
cue =[4,'NodeA',11,22,33,44,55,66,77,88,99]
class InitialInputs(scrolled.ScrolledPanel):
global cue
def __init__(self, parent, db):
scrolled.ScrolledPanel.__init__(self, parent, -1)
self.db = db
self.cur = self.db.con.cursor()
self.saveBtn = wx.Button(self, -1, "Save Current Values")
self.Bind(wx.EVT_BUTTON, self.onSave, self.saveBtn)
self.dirname = ""
def onSave(self, event):
global cue
dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.txt", wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
if dlg.ShowModal() == wx.ID_OK:
itcontains = cue
self.filename=dlg.GetFilename()
self.dirname=dlg.GetDirectory()
filehandle=open(os.path.join(self.dirname, self.filename),'w')
filehandle.write(str(itcontains))
filehandle.close()
dlg.Destroy()
row = cue[0] - 1
InsertCell ="UPDATE CUES SET 'Send'=?,'RED'=?,'GREEN'=?,'BLUE'=?,'RGB_Alpha'=?,'HUE'=?,'SAT'=?,'BRightness'=?,'HSB_Alpha'=?,'Fade'=? WHERE DTIndex=%i" %row
self.cur.execute(InsertCell, cue[1:])
self.db.con.commit()
GridPanel().grid.onAddCue() #This is the part that's not working
class Grid(gridlib.Grid):
global cue
def __init__(self, parent, db):
gridlib.Grid.__init__(self, parent, -1)
self.CreateGrid(20,10)
for row in range(20):
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 GridPanel(wx.Panel):
def __init__(self, parent, db):
wx.Panel.__init__(self, parent, -1)
self.db = db
self.cur = self.db.con.cursor()
grid = Grid(self, db)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(grid)
self.SetSizer(sizer)
self.Fit()
def onAddCue():
global cue
row = cue[0] - 1
col=0
while col < 10:
for i in cue[1:]:
grid.SetCellValue(row, col, str(i))
col = col+1
class GetDatabase():
def __init__(self, f):
# check db file exists
try:
file = open(f)
file.close()
except IOError:
# database doesn't exist - create file & populate it
self.exists = 0
else:
# database already exists - need integrity check here
self.exists = 1
self.con = sqlite.connect(f)
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1,"Stage Lighting", size=(800,600))
panel = wx.Panel(self)
notebook = wx.Notebook(panel)
page1 = InitialInputs(notebook, db)
page2 = GridPanel(notebook, db)
notebook.AddPage(page1, "Initial Inputs")
notebook.AddPage(page2, "Grid")
sizer = wx.BoxSizer()
sizer.Add(notebook, 1, wx.ALL|wx.EXPAND, 5)
panel.SetSizer(sizer)
self.Layout()
if __name__ == "__main__":
db = GetDatabase("data.db")
app = wx.App()
logging.basicConfig(level=logging.DEBUG)
Frame().Show()
app.MainLoop()
Apparently, the question is about python syntax errors!
onAddCue is a method belonging to the class GridPanel. The class is instantiated in the variable page2.
So, you need to call the method something like this:
page2.OnAddCue()
Related
I have a table in my MainWindow in which the data is coming from the MySQL Database.
There is a push button to add new item in that table. When you click on the Push Button, a new Window opens which contains the form. Once you have filled the form, and you press a "Add Section" button on the second window, it is supposed to perform these three things,
Insert the Given data back into the Database (this is working)
Close the Second Window (not working)
Update the Table in the Main Window with the new record.
Now, this is the basic function, which is getting the record from the database and displaying it in the Table on MainWindow,
def get_section_data(self):
mycursor = self.DB.cursor()
Subquery = "Select * from tbl_section"
mycursor.execute(Subquery)
numcols = len(mycursor.fetchall()[0])
mycursor.execute(Subquery)
numrows = len(mycursor.fetchall())
self.ui.section_table.setRowCount(numrows)
self.ui.section_table.setColumnCount(numcols)
mycursor.execute(Subquery)
tablerow = 0
for row in mycursor.fetchall():
tablecol = 0
while tablecol < numcols:
self.ui.section_table.setItem(tablerow, tablecol, PySide2.QtWidgets.QTableWidgetItem(str(row[tablecol])))
tablecol += 1
tablerow += 1
this is the function which gets called when you click on "Add Section" on the Main Window (this opens the New Form)
def executeAddSectionPage(self):
self.window = QtWidgets.QMainWindow()
self.add_section_form = Ui_Add_Section_Window()
self.add_section_form.setupUi(self.window)
self.window.show()
self.add_section_form.section_add_form_button.clicked.connect(self.insert_section_info)
Following is the function which is called when you click on the "Add Section" in the 2nd form,
def insert_section_info(self):
id = self.add_section_form.section_id_add.text()
name = self.add_section_form.section_name_add.text()
mycursor = self.DB.cursor()
sql = "Insert into tbl_section (section_id, section_name) VALUES (%s, %s)"
val = (int(id), name)
mycursor.execute(sql, val)
self.DB.commit()
# self.add_section_form.hide() -> I tried to add this but it didn't work
When I click on the "Add Section" button on my second window, it doesn't do anything (except storing the record in the database at backend)
When I again click on it, it crashes both the windows.
How can I perform the functionalities that I require?
Following is the complete code of my main.py
## IMPORTS
import sys
import os
import PySide2
import mysql.connector as mc
from qt_material import *
from PyQt5 import QtWidgets, uic
from add_section_page import Ui_Add_Section_Window
#####################################
# Import GUI File
from ui_interface import *
######################################
# class Add_Section(QMainWindow):
# def __init__(self):
# super(Add_Section, self).__init__()
# self.uic.loadUi('add_section_page.ui', self)
## Main Window Class
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
try:
self.DB = mc.connect(host="localhost", user="root", password="", database="timetable_manager")
except mc.Error as e:
print("Error")
# Load Style Sheet
apply_stylesheet(app, theme="dark_cyan.xml")
# Remove Window Title Bar
self.setWindowFlags(PySide2.QtCore.Qt.FramelessWindowHint)
# Set main background to transparent
self.setAttribute(PySide2.QtCore.Qt.WA_TranslucentBackground)
# Shadow Style Effect
self.shadow = QGraphicsDropShadowEffect(self)
self.shadow.setBlurRadius(50)
self.shadow.setXOffset(0)
self.shadow.setYOffset(0)
self.shadow.setColor(QColor(0, 92, 157, 550))
# Apply shadow to central widget
self.ui.centralwidget.setGraphicsEffect(self.shadow)
self.setWindowIcon(PySide2.QtGui.QIcon(":/icons/airplay.svg"))
# Set Window Title
self.setWindowTitle("Timetable Manager")
# Window Size grip to resize window
QSizeGrip(self.ui.size_grip)
# Minimize Window
self.ui.minimize_window_button.clicked.connect(lambda: self.showMinimized())
# Close Window
self.ui.close_window_button.clicked.connect(lambda: self.close())
# Maximize Window
self.ui.restore_window_button.clicked.connect(lambda: self.restore_or_maximize_window())
# Navigate to Section Page
self.ui.section_menu_button.clicked.connect(lambda: self.ui.stackedWidget.setCurrentWidget(self.ui.section_page))
self.ui.course_menu_button.clicked.connect(lambda: self.ui.stackedWidget.setCurrentWidget(self.ui.course_page))
self.ui.add_section_button.clicked.connect(self.executeAddSectionPage)
self.show()
self.get_section_data()
def executeAddSectionPage(self):
self.window = QtWidgets.QMainWindow()
self.add_section_form = Ui_Add_Section_Window()
self.add_section_form.setupUi(self.window)
self.window.show()
self.add_section_form.section_add_form_button.clicked.connect(self.insert_section_info)
def insert_section_info(self):
id = self.add_section_form.section_id_add.text()
name = self.add_section_form.section_name_add.text()
mycursor = self.DB.cursor()
sql = "Insert into tbl_section (section_id, section_name) VALUES (%s, %s)"
val = (int(id), name)
mycursor.execute(sql, val)
self.DB.commit()
# self.add_section_form.hide() -> I tried to add this but it didn't work
def get_section_data(self):
mycursor = self.DB.cursor()
Subquery = "Select * from tbl_section"
mycursor.execute(Subquery)
numcols = len(mycursor.fetchall()[0])
mycursor.execute(Subquery)
numrows = len(mycursor.fetchall())
self.ui.section_table.setRowCount(numrows)
self.ui.section_table.setColumnCount(numcols)
mycursor.execute(Subquery)
tablerow = 0
for row in mycursor.fetchall():
tablecol = 0
while tablecol < numcols:
self.ui.section_table.setItem(tablerow, tablecol, PySide2.QtWidgets.QTableWidgetItem(str(row[tablecol])))
tablecol += 1
tablerow += 1
def restore_or_maximize_window(self):
if self.isMaximized():
self.showNormal()
#self.ui.restore_window_button.setIcon()
else:
self.showMaximized()
#self.ui.restore_window_button.setIcon()
#def get_section_data(self):
# sqlquery = "SELECT * FROM tbl_section"
# cur = self.db.cursor()
# for row in cur.execute(sqlquery):
# print(row)
## EXECUTE APP
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
Hello Everyone i need help why my output result is none in the print('bla bla') line so from my output is None, None, None that actually insert from npm , nama , and jurusan but the output is none ,can anybody help me solve it thanks
import sqlite3
import tkinter
from tkinter import *
from tkinter import ttk
def Daftar():
window = Tk()
window.title("Welcome to TutorialsPoint")
window.geometry('400x400')
window.configure(background = "grey");
Lnpm = Label(window, text="Please Input Your npm: ").grid(row=0, column=0)
Lnama = Label(window,text="Please Input Your nama: ").grid(row=1, column=0)
Ljurusan = Label(window,text="Please Input Your jurusan: ").grid(row=2, column=0)
npm = Entry(window).grid(row = 0,column = 1)
nama = Entry(window).grid(row = 1,column = 1)
jurusan = Entry(window).grid(row = 2,column = 1)
def Clicked():
print("First Name: %s\nLast Name: %s\nLast Name: %s" % (npm, nama, jurusan))
connect = sqlite3.connect('Presensi.db')
cur = connect.cursor()
connect.execute("INSERT OR IGNORE INTO user(npm,nama,jurusan) values(?,?,?)", (str(npm),str(nama),str(jurusan)))
connect.execute("INSERT OR IGNORE INTO presensi(nama) values(?)", (str(nama),))
connect.commit()
cur.close()
btn = ttk.Button(window ,text="Register",command= Clicked()).grid(row=3,column=0)
window.mainloop()
You've got two big issues here:
the grid() function of the Entry object returns None and that's what npm, nama and jurusan are None. What you have to do is store the Entry object, not the value returned from grid().
you're not calling get() on the Entry objects to get their input values
What you can do is create a class in which you store the Entry objects. The callback function of the Button object can then be a method of the class.
I've reorganised your code to do this:
from tkinter import Tk, Label, Button, Entry
import sqlite3
class Daftar:
def __init__(self, master):
self.window = master
self.window.title("Welcome to TutorialsPoint")
self.window.geometry('400x400')
self.window.configure(background = "grey");
self.Lnpm = Label(self.window, text="Please Input Your npm: ").grid(row=0, column=0)
self.Lnama = Label(self.window,text="Please Input Your nama: ").grid(row=1, column=0)
self.Ljurusan = Label(self.window,text="Please Input Your jurusan: ").grid(row=2, column=0)
#Entry objects for later use
self.npm = Entry(self.window)
self.npm.grid(row = 0,column = 1)
self.nama = Entry(self.window)
self.nama.grid(row = 1,column = 1)
self.jurusan = Entry(self.window)
self.jurusan.grid(row = 2,column = 1)
self.btn = Button(self.window ,text="Register",command = self.Clicked).grid(row=3,column=0)
def Clicked(self):
#Get the entry values
npm = self.npm.get()
nama = self.nama.get()
jurusan = self.jurusan.get()
print("First Name: %s\nLast Name: %s\nLast Name: %s" % (npm, nama, jurusan))
connect = sqlite3.connect('Presensi.db')
cur = connect.cursor()
connect.execute("INSERT OR IGNORE INTO user(npm,nama,jurusan) values(?,?,?)", (npm,nama,jurusan))
connect.execute("INSERT OR IGNORE INTO presensi(nama) values(?)", (nama,))
connect.commit()
cur.close()
root = Tk()
my_gui = Daftar(root)
root.mainloop()
window.mainloop()
When you click on QScrollBar's "page control area" ('c' on the image), it will scroll one page. What I want is to make it scroll to the full, just like when you choose "Scroll here" context menu item.
That's quite an interesting question. To find out an answer, we need to take a look at QScrollBar source and find out two things:
How to determine which part of the scroll bar has been clicked;
How to trigger "Scroll Here" behavior.
The answer to the first question lies in QScrollBar::mousePressEvent implementation. It turns out that QStyle::hitTestComplexControl does just what we need. What for the second question, just search "Scroll here" and you'll see that QScrollBarPrivate::pixelPosToRangeValue is used to convert event position to slider value. Unfortunately, we don't have access to functions of this private class, so we're forced to reimplement it. Now let's apply gained knowledge and implement new behavior in a subclass:
import sys
from PyQt4 import QtCore, QtGui
class ModifiedScrollBar(QtGui.QScrollBar):
def __init__(self, parent = None):
super(ModifiedScrollBar, self).__init__(parent)
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
opt = QtGui.QStyleOptionSlider()
self.initStyleOption(opt)
control = self.style().hitTestComplexControl(QtGui.QStyle.CC_ScrollBar, opt,
event.pos(), self)
if (control == QtGui.QStyle.SC_ScrollBarAddPage or
control == QtGui.QStyle.SC_ScrollBarSubPage):
# scroll here
gr = self.style().subControlRect(QtGui.QStyle.CC_ScrollBar, opt,
QtGui.QStyle.SC_ScrollBarGroove, self)
sr = self.style().subControlRect(QtGui.QStyle.CC_ScrollBar, opt,
QtGui.QStyle.SC_ScrollBarSlider, self)
if self.orientation() == QtCore.Qt.Horizontal:
pos = event.pos().x()
sliderLength = sr.width()
sliderMin = gr.x()
sliderMax = gr.right() - sliderLength + 1
if (self.layoutDirection() == QtCore.Qt.RightToLeft):
opt.upsideDown = not opt.upsideDown
else:
pos = event.pos().y()
sliderLength = sr.height()
sliderMin = gr.y()
sliderMax = gr.bottom() - sliderLength + 1
self.setValue(QtGui.QStyle.sliderValueFromPosition(
self.minimum(), self.maximum(), pos - sliderMin,
sliderMax - sliderMin, opt.upsideDown))
return
return super(ModifiedScrollBar, self).mousePressEvent(event)
def main():
app = QtGui.QApplication(sys.argv)
edit = QtGui.QTextEdit()
#uncomment for testing horizontal scrollbar
#edit.setLineWrapMode(QtGui.QTextEdit.NoWrap)
edit.setPlainText("Lorem ipsum...")
edit.setVerticalScrollBar(ModifiedScrollBar())
edit.setHorizontalScrollBar(ModifiedScrollBar())
edit.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Works for me, python 3.4 pyqt 5.4.
pixelPosToRangeValue is taken from qt source
def wrapEF(ef):
w = QObject()
w.eventFilter = ef
return w
def sbEventFilter(s, e):
q = s
if (e.type() == QEvent.MouseButtonPress and e.button() == Qt.LeftButton
or e.type() == QEvent.MouseButtonDblClick):
#pixelPosToRangeValue(pos)
opt = QStyleOptionSlider()
q.initStyleOption(opt)
gr = q.style().subControlRect(QStyle.CC_ScrollBar, opt,
QStyle.SC_ScrollBarGroove, q)
sr = q.style().subControlRect(QStyle.CC_ScrollBar, opt,
QStyle.SC_ScrollBarSlider, q)
if q.orientation() == Qt.Horizontal:
sliderLength = sr.width()
sliderMin = gr.x()
sliderMax = gr.right() - sliderLength + 1
if q.layoutDirection() == Qt.RightToLeft:
opt.upsideDown = not opt.upsideDown
dt = sr.width()/2
pos = e.pos().x()
else:
sliderLength = sr.height()
sliderMin = gr.y()
sliderMax = gr.bottom() - sliderLength + 1
dt = sr.height()/2
pos = e.pos().y()
r = QStyle.sliderValueFromPosition(q.minimum(), q.maximum(),
pos - sliderMin - dt,
sliderMax - sliderMin, opt.upsideDown)
#pixelPosToRangeValue,
q.setValue(r)
return q.eventFilter(s, e)
self.scrollBarEF = wrapEF(sbEventFilter)
self.hscrollbar.installEventFilter(self.scrollBarEF)
self.vscrollbar.installEventFilter(self.scrollBarEF)
I am a beginner in tkinter. I am making a list of names. You can delete, select and edit it, but if I don't select anything in the list and click these buttons, it says:
Exception in Tkinter callback Traceback (most recent call last): File
"C:\Python34\lib\tkinter\__init__.py", line 1533, in __call__ return
self.func(*args) File "C:\Users\user\Desktop\HOW_TOUGH - NEW\Change_user.py",
line 60, in Edit (idx, ) = d ValueError: need more than 0 values to unpack'''
I am planning to disable the buttons if the user doesn't click anything but I am not expert enough. Here's my code (it's a child window)
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
class Nick:
def __init__(self, master ):
self.master = master
self.window = Toplevel(master)
self.window.title('Change User')
self.window.geometry('300x300')
self.window.minsize(300, 300)
self.window.maxsize(300, 300)
self.nickname = StringVar()
self.lb = Listbox(self.window, selectmode = 'SINGLE')
f= open('users.txt','r')
rec = f.readlines()
f.close()
for i in rec:
p = i.find('|')
nickname = i[:p]
self.lb.insert(END, nickname)
self.lb.pack()
self.Ed = ttk.Button(self.window, text = 'Edit', command = self.Edit).pack()
self.Del = ttk.Button(self.window, text = 'Delete', command = self.Delete).pack()
self.Bac = ttk.Button(self.window, text = 'Back', command = self.Back).pack()
self.Okay = ttk.Button(self.window, text = 'Ok', command = self.Ok).pack()
def Back(self):
self.window.destroy()
def Delete(self):
d = self.lb.curselection()
(idx, ) = d
self.lb.delete(idx)
f = open('users.txt','r')
r = f.readlines()
f.close()
rec = r[idx]
r.remove(rec)
f = open('users.txt','w')
new = ''.join(r)
r = f.write(new)
f.close()
messagebox.showinfo(title='Success', message = 'Delete successful')
def Edit(self):
d = self.lb.curselection()
(idx, ) = d
import Edit as Edet
Edet.Edit(self.master, idx)
def Ok(self):
d = self.lb.curselection()
(idx, ) = d
get = self.lb.get(idx)
self.window.destroy()
print (get)
print (d)
The method curselection() returns an empty tuple when nothing is selected. You can skip those methods just by adding a
if not d:
return
If you want to gray out your buttons, you can do this:
button["state"] = DISABLED
Note that this won't work currently with your code as you did this:
self.button = ttk.Button(...).pack()
The problem lies in the call of pack() which returns None, effectively binding self.button to None. Just assign the button object to the variable first and then pack it. Furthermore, it's not recommended to import * from Tkinter because you're dropping ~190 names in your namespace. Just use
import tkinter as tk
hi i am very new to python so please help even if you feel i am asking a silly doubt. the thing is i am creating five lineedits from which values have to be extracted on click of button. but the problem is on click of button i am getting interfaceerror:Error binding parameter 0 - probably unsupported type. Below is my code:
class NewWindow(QtGui.QDialog):
def __init__(self, parent=None):
super(NewWindow, self).__init__(parent)
self.group1= QtGui.QGroupBox("Add Data")
self.patientName = QtGui.QLabel("Name")
self.patientEdit = QtGui.QLineEdit()
self.patientid = QtGui.QLabel("Id")
self.patientidEdit = QtGui.QLineEdit()
self.patientidEdit.setValidator(QtGui.QIntValidator(self.patientidEdit))
self.age = QtGui.QLabel("Age")
self.ageEdit = QtGui.QLineEdit()
self.ageEdit.setValidator(QtGui.QIntValidator(self.ageEdit))
self.genderlabel = QtGui.QLabel("Gender")
self.patientgend = QtGui.QLineEdit()
self.eyeType = QtGui.QLabel("Eye Type")
self.eyeTypeEdit = QtGui.QLineEdit()
self.AddData = QtGui.QPushButton("Add Data")
self.AddData.clicked.connect(self.AddData_clicked)
self.databaseLayout = QtGui.QGridLayout()
self.databaseLayout.addWidget(self.patientName,0,0)
self.databaseLayout.addWidget(self.patientEdit,0,1)
self.databaseLayout.addWidget(self.patientid,2,0)
self.databaseLayout.addWidget(self.patientidEdit,2,1)
self.databaseLayout.addWidget(self.age,4,0)
self.databaseLayout.addWidget(self.ageEdit,4,1)
self.databaseLayout.addWidget(self.genderlabel,6,0)
self.databaseLayout.addWidget(self.patientgend,6,1)
self.databaseLayout.addWidget(self.eyeType,8,0)
self.databaseLayout.addWidget(self.eyeTypeEdit,8,1)
self.databaseLayout.addWidget(self.AddData,10,10)
self.group1.setLayout(self.databaseLayout)
mainLayout = QtGui.QVBoxLayout()
mainLayout.addWidget(self.group1)
mainLayout.addStretch(1)
self.setLayout(mainLayout)
def AddData_clicked(self):
self.db_con = sqlite3.Connection
self.db_name = "./patientData.db"
self.createDb = sqlite3.connect(self.db_name)
self.queryCurs = self.createDb.cursor()
self.name = self.patientEdit.text()
self.id = self.patientidEdit.text()
self.age = self.ageEdit.text()
self.gender = self.patientgend.text()
self.eye_type = self.eyeTypeEdit.text()
self.queryCurs.execute('''CREATE TABLE IF NOT EXISTS PATIENT
(NAME TEXT NOT NULL, ID INTEGER PRIMARY KEY, AGE INTEGER NOT NULL, GENDER TEXT NOT NULL, EYE_TYPE TEXT NOT NULL)''')
self.queryCurs.execute('''INSERT INTO PATIENT(NAME, ID, AGE, GENDER, EYE_TYPE)
VALUES(?,?,?,?,?)''',(self.name,self.id,self.age,self.gender,self.eye_type))
print ('inserted row')
please help me, where am i going wrong........
i am getting error at line VALUES(?,?,?,?,?).......