PyQt4 close tab that request closing - tabs

I cannot find a way to close the tab that request to be closed. I only found how to close current widget and current tab. Any ideas? I can't find a clue on internet.
self.tabs.tabCloseRequested.connect(self.removeTab)
def removeTab(self):
tab = self.tabs.currentWidget()
tab.deleteLater()

The QTabWidget class has a removeTab method, which will remove a tab, but without deleting its content widget. So you will also need to delete the content widget explicitly:
self.tabs.tabCloseRequested.connect(self.removeTab)
...
def removeTab(self, index):
widget = self.tabs.widget(index)
if widget is not None:
widget.deleteLater()
self.tabs.removeTab(index)

I can post you the code, but it's a bit confused.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import codecs
import os
class Central_widget(QWidget):
def __init__(self, setted_lang):
super(Central_widget, self).__init__()
#tab list
self.tab_list = {}
self.cont_list = {}
self.label_list = {}
self.label_num = 0
self.tab_num = 0
#main page contenent
lesson = codecs.open('lessons\lekcja.html', 'r', encoding='utf-8' )
self.read = lesson.read()
read2 = self.read.encode('utf8')
print read2
#General widget
self.general = QWidget(self)
self.general.resize(900, 700)
#leftWidget
self.leftWidget=QWidget(self.general)
self.leftWidget.resize(160 ,657)
#tab master
self.tabmaster(self.general)
def tabmaster(self, general):
#left widget
self.scrollarea()
#right widget
self.tabs = QTabWidget(self.general)
self.tabs.setTabsClosable(True)
self.tabs.setTabEnabled(self.tab_num, True)
self.tabs.resize(710, 640)
self.tabs.move(170, 9)
#actual open tabs
self.actual_numtabs = self.tabs.indexOf(self.tabs.currentWidget())
#homepage tab
self.new_tab('hey')
def new_tab(self, text):
#tab_name - tab_value dictionary
if self.tab_num == 0:
name_new_tab = 'Homepage'
else: name_new_tab = 'Karta '+str(self.tab_num)
value_new_tab = QWidget()
self.tab_list[name_new_tab] = value_new_tab
#tab_content and cont_value
tab_content = 'cont '+str(self.tab_num)
cont_value = QTextBrowser(self.tab_list[name_new_tab])
self.cont_list[tab_content] = cont_value
#set size, text, add widget to tab
self.tabs.addTab(self.tab_list[name_new_tab], str(name_new_tab))
self.cont_list[tab_content].setFixedSize(704, 614)
if self.tab_num == 0:
self.cont_list[tab_content].setText(self.read)
self.tabs.setCurrentWidget(self.tab_list[name_new_tab])
else: self.cont_list[tab_content].setText(text)
#close tab
self.tabs.tabCloseRequested.connect(self.removeTab)
self.tab_num += 1
def removeTab(self, index):
#remove tab from widget
widget = self.tabs.widget(index)
if widget is not None:
widget.deleteLater()
self.tabs.removeTab(index)
def scrollarea(self):
#scroll area
layoutleft = QVBoxLayout(self.leftWidget)
s=QScrollArea()
layoutleft.addWidget(s)
widleft = QWidget(self)
vbox=QVBoxLayout(widleft)
nl=QHBoxLayout()
nl.addWidget(QLabel(u"Lista lekcji dostępnych:", self))
vbox.addLayout(nl)
nl=QHBoxLayout()
vbox.addLayout(nl)
vbox.setSpacing(2)
vbox.insertSpacing(1, 20)
#list of lessons
for filename in os.listdir('lessons'):
name = os.path.splitext(filename)
label_var = name[0]
value = QPushButton(label_var)
self.label_list[label_var] = value
self.label_list[label_var].clicked.connect(self.openlesson)
self.label_list[label_var].setObjectName(label_var)
_l=QHBoxLayout()
_l.addWidget(self.label_list[label_var])
vbox.addLayout(_l)
s.setWidget(widleft)
def openlesson(self):
a = self.sender()
print a.objectName()
lesson = codecs.open('lessons\\'+str(a.objectName())+'.html', 'r', encoding='utf-8' )
read = lesson.read()
self.new_tab(read)

Related

Show and hide tab widgets dynamically with pySide

If I create my UI in QT Designer (and import UI to the script), how can I hide and show tabs in my script?
class Tool(QMainWindow, uiTool.Ui_Tool):
def __init__(self):
super(Tool, self).__init__()
# SETUP UI
self.setupUi(self)
# self.tabWidget.removeTab() ???
There is no way to hide/show the tabs in a tab-widget, so you will need to remove and replace them instead.
Below is a demo script that shows how to do this. I have not attempted to keep track of the original indexes in this example - it just shows the basic usage of the methods involved:
import sys
from PyQt5 import QtCore, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(354, 268)
self.gridLayout = QtWidgets.QGridLayout(Form)
self.gridLayout.setObjectName("gridLayout")
self.tabWidget = QtWidgets.QTabWidget(Form)
self.tabWidget.setObjectName("tabWidget")
self.tabRed = QtWidgets.QWidget()
self.tabRed.setObjectName("tabRed")
self.tabWidget.addTab(self.tabRed, "")
self.tabBlue = QtWidgets.QWidget()
self.tabBlue.setObjectName("tabBlue")
self.tabWidget.addTab(self.tabBlue, "")
self.tabGreen = QtWidgets.QWidget()
self.tabGreen.setObjectName("tabGreen")
self.tabWidget.addTab(self.tabGreen, "")
self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 2)
self.buttonRemove = QtWidgets.QPushButton(Form)
self.buttonRemove.setObjectName("buttonRemove")
self.gridLayout.addWidget(self.buttonRemove, 1, 0, 1, 1)
self.buttonRestore = QtWidgets.QPushButton(Form)
self.buttonRestore.setObjectName("buttonRestore")
self.gridLayout.addWidget(self.buttonRestore, 1, 1, 1, 1)
self.retranslateUi(Form)
self.tabWidget.setCurrentIndex(2)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabRed), _translate("Form", "Red"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabBlue), _translate("Form", "Blue"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabGreen), _translate("Form", "Green"))
self.buttonRemove.setText(_translate("Form", "Remove"))
self.buttonRestore.setText(_translate("Form", "Restore"))
class Window(QtWidgets.QWidget, Ui_Form):
def __init__(self):
super(Window, self).__init__()
self.setupUi(self)
self.buttonRemove.clicked.connect(self.handleButtonRemove)
self.buttonRestore.clicked.connect(self.handleButtonRestore)
self.tab_pages = []
for index in range(self.tabWidget.count()):
self.tab_pages.append((
self.tabWidget.widget(index),
self.tabWidget.tabText(index),
))
def handleButtonRemove(self):
index = self.tabWidget.currentIndex()
if index >= 0:
self.tabWidget.removeTab(index)
def handleButtonRestore(self):
for page, title in self.tab_pages:
if self.tabWidget.indexOf(page) < 0:
self.tabWidget.addTab(page, title)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.setGeometry(600, 100, 300, 200)
window.show()
sys.exit(app.exec_())

Retrieving MySQL with Kivy

I have a Kivy code, where the output is:
I want to get replace the Box No. with strings retrieved from MySQL
So far I have tried to implement the MySQL to the python script:
class RemoveScreen(MyLayout):
def __init__(self,**kwargs):
db = MySQLdb.connect("localhost", "root", "[PASSWORD]", "tcs_microrage_crm")
cursor=db.cursor()
self.var = StringVar()
self.label1 = Label(self, text=0, textvariable=self.var)
myvar=str(self.var)
#http://stackoverflow.com/questions/775296/python-mysql-parameterized-queries
cursor.execute("SELECT part_name FROM stock_lists WHERE part_number = %s", (myvar))
self.myvar=StringVar()
self.myvar.set(cursor.fetchone())
self.label2 = Label(self, text=0, textvariable=myvar)
But this didn't work.
Q: How can I do MySQL queries and print individual strings in the kv file.
To show you how you could do that, I made a little search example.
This searches for fruit names in the database, and will output its name and price to the table.
from kivy.app import App
import MySQLdb
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
class DbCon:
def __init__(self):
self.db = MySQLdb.connect(user="root",passwd="pw",db="kivy")
self.c = self.db.cursor()
def get_rows(self,search = ""):
self.c.execute("SELECT * FROM fruit WHERE name REGEXP '.*%s.*' LIMIT 3" % search)
return self.c.fetchall()
class Table(BoxLayout):
def __init__(self,**kwargs):
super(Table,self).__init__(**kwargs)
self.orientation = "vertical"
self.search_field = BoxLayout(orientation="horizontal")
self.search_input = TextInput(text='search',multiline=False)
self.search_button = Button(text="search",on_press=self.search)
self.search_field.add_widget(self.search_input)
self.search_field.add_widget(self.search_button)
self.add_widget(self.search_field)
self.add_widget(Label(text="table"))
self.table = GridLayout(cols=2,rows=4)
self.table.add_widget(Label(text="Fruit"))
self.table.add_widget(Label(text="Price"))
self.rows = [[Label(text="item"),Label(text="price")],
[Label(text="item"),Label(text="price")],
[Label(text="item"),Label(text="price")]]
for item,price in self.rows:
self.table.add_widget(item)
self.table.add_widget(price)
self.add_widget(self.table)
self.db = DbCon()
self.update_table()
def update_table(self,search=""):
for index,row in enumerate(self.db.get_rows(search)):
self.rows[index][0].text = row[1]
self.rows[index][1].text = str(row[2])
def clear_table(self):
for index in range(3):
self.rows[index][0].text = ""
self.rows[index][1].text = ""
def search(self, *args):
self.clear_table()
self.update_table(self.search_input.text)
class MyApp(App):
def build(self):
return Table()
MyApp().run()

Fail to store data in csv file through scraping

I try to scraping a webpage and extracting data ,then store all data in a csv file. Before adding ScrapeCallback class and calling it, everything works fine. However, it does not store any type of data except headers in the cvs file after adding the new class. Can anyone help me to figure out the problem?
import re
import urlparse
import urllib2
import time
from datetime import datetime
import robotparser
import Queue
import csv
import lxml.html
class ScrapeCallback:
# extract and store all data in a csv file
def __init__( self):
self.writer = csv.writer(open('countries.csv', 'w'))
self.fields = ('area', 'population', 'iso', 'country', 'capital', 'continent', 'tld', 'currency_code', 'currency_name', 'phone', 'postal_code_format', 'postal_code_regex', 'languages', 'neighbours')
self.writer.writerow( self.fields)
def __call__( self, url, html):
if re.search('/view/',url):
tree = lxml.html.fromstring(html)
row = []
for field in self.fields:
row.append(tree.cssselect('table > tr#places_{}__row > td.w2p_fw'.format(field))[0].text_content())
print row
self.writer.writerow(row)
def link_crawler(seed_url, link_regex=None, delay=5, max_depth=-1, max_urls=-1, headers=None, user_agent='wswp', proxy=None, num_retries=1, scrape_callback=None):
"""Crawl from the given seed URL following links matched by link_regex
"""
# the queue of URL's that still need to be crawled
crawl_queue = [seed_url]
# the URL's that have been seen and at what depth
seen = {seed_url: 0}
# track how many URL's have been downloaded
num_urls = 0
rp = get_robots(seed_url)
throttle = Throttle(delay)
headers = headers or {}
if user_agent:
headers['User-agent'] = user_agent
while crawl_queue:
url = crawl_queue.pop()
depth = seen[url]
# check url passes robots.txt restrictions
if rp.can_fetch(user_agent, url):
throttle.wait(url)
html = download(url, headers, proxy=proxy, num_retries=num_retries)
links = []
if scrape_callback:
links.extend(scrape_callback(url, html) or [])
if depth != max_depth:
# can still crawl further
if link_regex:
# filter for links matching our regular expression
links.extend(link for link in get_links(html) if re.match(link_regex, link))
for link in links:
link = normalize(seed_url, link)
# check whether already crawled this link
if link not in seen:
seen[link] = depth + 1
# check link is within same domain
if same_domain(seed_url, link):
# success! add this new link to queue
crawl_queue.append(link)
# check whether have reached downloaded maximum
num_urls += 1
if num_urls == max_urls:
break
else:
print 'Blocked by robots.txt:', url
class Throttle:
"""Throttle downloading by sleeping between requests to same domain
"""
def __init__(self, delay):
# amount of delay between downloads for each domain
self.delay = delay
# timestamp of when a domain was last accessed
self.domains = {}
def wait(self, url):
"""Delay if have accessed this domain recently
"""
domain = urlparse.urlsplit(url).netloc
last_accessed = self.domains.get(domain)
if self.delay > 0 and last_accessed is not None:
sleep_secs = self.delay - (datetime.now() - last_accessed).seconds
if sleep_secs > 0:
time.sleep(sleep_secs)
self.domains[domain] = datetime.now()
def download(url, headers, proxy, num_retries, data=None):
print 'Downloading:', url
request = urllib2.Request(url, data, headers)
opener = urllib2.build_opener()
if proxy:
proxy_params = {urlparse.urlparse(url).scheme: proxy}
opener.add_handler(urllib2.ProxyHandler(proxy_params))
try:
response = opener.open(request)
html = response.read()
code = response.code
except urllib2.URLError as e:
print 'Download error:', e.reason
html = ''
if hasattr(e, 'code'):
code = e.code
if num_retries > 0 and 500 <= code < 600:
# retry 5XX HTTP errors
html = download(url, headers, proxy, num_retries-1, data)
else:
code = None
return html
def normalize(seed_url, link):
"""Normalize this URL by removing hash and adding domain
"""
link, _ = urlparse.urldefrag(link) # remove hash to avoid duplicates
return urlparse.urljoin(seed_url, link)
def same_domain(url1, url2):
"""Return True if both URL's belong to same domain
"""
return urlparse.urlparse(url1).netloc == urlparse.urlparse(url2).netloc
def get_robots(url):
"""Initialize robots parser for this domain
"""
rp = robotparser.RobotFileParser()
rp.set_url(urlparse.urljoin(url, '/robots.txt'))
rp.read()
return rp
def get_links(html):
"""Return a list of links from html
"""
# a regular expression to extract all links from the webpage
webpage_regex = re.compile('<a[^>]+href=["\'](.*?)["\']', re.IGNORECASE)
# list of all links from the webpage
return webpage_regex.findall(html)
if __name__ == '__main__':
# link_crawler('http://example.webscraping.com', '/(index|view)', delay=0, num_retries=1, user_agent='BadCrawler')
# link_crawler('http://example.webscraping.com', '/(index|view)', delay=0, num_retries=1, max_depth=1, user_agent='GoodCrawler')
link_crawler('http://example.webscraping.com', '/(index|view)', max_depth =2, scrape_callback = ScrapeCallback())

deleting a parent widget through a child QPushButton pyqt

It's been a while I'm searching all over the internet for that, but still couldn't get the answer... basically I have a QVBoxLayout which contains several frames - and each frame contains a button which function is to delete its parent frame. The main code was created using QT Designer and pyuic4. I wrote the two additional functions, one works perfectly ("createFrame") but I'm struggling with the "deleteFrame" one. the label inside the frame shows the index of that frame in the vert_layout "array". the problem I noted on my code is that, using it that way, I can only delete the last frame added. So, can someone help me with this issue?
please see my code below:
# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui
import sys
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
#Custom button that sends out its own instance as the signal
class MyPushButton(QtGui.QPushButton):
mySignal = QtCore.pyqtSignal(QtGui.QWidget)
def mousePressEvent(self, *args, **kwargs):
self.mySignal.emit(self)
class Functions:
def createFrame(self,mainWindow):
#just local frame no need to store it in the class
frame = QtGui.QFrame()
frame.setGeometry(QtCore.QRect(10, 10, 241, 61))
frame.setFrameShape(QtGui.QFrame.StyledPanel)
frame.setFrameShadow(QtGui.QFrame.Raised)
frame.setObjectName(_fromUtf8("frame"))
pushButton_2 = MyPushButton(frame)
pushButton_2.setGeometry(QtCore.QRect(94, 10, 141, 41))
pushButton_2.setObjectName(_fromUtf8("pushButton_2"))
label = QtGui.QLabel(frame)
label.setGeometry(QtCore.QRect(20, 10, 71, 41))
label.setFrameShape(QtGui.QFrame.NoFrame)
label.setAlignment(QtCore.Qt.AlignCenter)
#the vert_layout belongs to class Ui_MainWindow
mainWindow.vert_layout.addWidget(frame)
label.setObjectName(_fromUtf8("label"))
label.setText(str(mainWindow.vert_layout.indexOf(frame)))
pushButton_2.setText(_translate("MainWindow", "delete this frame and all\n its childs", None))
pushButton_2.mySignal.connect(self.deleteFrame)
#my initial idea was to include the mainWindow (instance of
#Ui_MainWindow class in order to use vert_layout - but apparently
#I need to modify the signal as well, right?
def deleteFrame(self,ref,mainWindow):
#finding the index of the FRAME (mybutton's parent)
#that is to be deleted
frame = mainWindow.vert_layout.itemAt(self.vert_layout.indexOf(ref.parent()))
widget = frame.widget()
if widget is not None:
widget.deleteLater()
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(400, 284)
self.vert_layout = QtGui.QVBoxLayout()
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.scrollArea = QtGui.QScrollArea(self.centralwidget)
self.scrollArea.setGeometry(QtCore.QRect(10, 10, 281, 261))
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setObjectName(_fromUtf8("scrollArea"))
self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.scrollAreaWidgetContents = QtGui.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 277, 257))
self.scrollAreaWidgetContents.setObjectName(_fromUtf8("scrollAreaWidgetContents"))
self.scrollAreaWidgetContents.setLayout(self.vert_layout)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.pushButton = QtGui.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(310, 20, 75, 23))
self.pushButton.setObjectName(_fromUtf8("pushButton"))
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
f = Functions()
self.pushButton.clicked.connect(lambda: f.createFrame())
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
self.pushButton.setText(_translate("MainWindow", "create", None))
class Main(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
if __name__== '__main__':
app = QtGui.QApplication(sys.argv)
window = Main()
window.show()
sys.exit(app.exec_())
All you are currently doing is deleting the self.frame widget each time.
So only the last created one gets deleted. And not the one you actually click on.
Modified your code for what you need. Hope it helps you understand.
# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui
import sys
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
#Custom button that sends out its own instance as the signal
class MyPushButton(QtGui.QPushButton):
mySignal = QtCore.pyqtSignal(QtGui.QWidget)
def mousePressEvent(self, *args, **kwargs):
self.mySignal.emit(self)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(400, 284)
self.vert_layout = QtGui.QVBoxLayout()
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.scrollArea = QtGui.QScrollArea(self.centralwidget)
self.scrollArea.setGeometry(QtCore.QRect(10, 10, 281, 261))
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setObjectName(_fromUtf8("scrollArea"))
self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.scrollAreaWidgetContents = QtGui.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 277, 257))
self.scrollAreaWidgetContents.setObjectName(_fromUtf8("scrollAreaWidgetContents"))
self.scrollAreaWidgetContents.setLayout(self.vert_layout)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.pushButton = QtGui.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(310, 20, 75, 23))
self.pushButton.setObjectName(_fromUtf8("pushButton"))
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.pushButton.clicked.connect(lambda: self.createFrame())
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
self.pushButton.setText(_translate("MainWindow", "create", None))
def createFrame(self):
#just local frame no need to store it in the class
frame = QtGui.QFrame()
frame.setGeometry(QtCore.QRect(10, 10, 241, 61))
frame.setFrameShape(QtGui.QFrame.StyledPanel)
frame.setFrameShadow(QtGui.QFrame.Raised)
frame.setObjectName(_fromUtf8("frame"))
pushButton_2 = MyPushButton(frame)
pushButton_2.setGeometry(QtCore.QRect(94, 10, 141, 41))
pushButton_2.setObjectName(_fromUtf8("pushButton_2"))
label = QtGui.QLabel(frame)
label.setGeometry(QtCore.QRect(20, 10, 71, 41))
label.setFrameShape(QtGui.QFrame.NoFrame)
label.setAlignment(QtCore.Qt.AlignCenter)
self.vert_layout.addWidget(frame)
label.setObjectName(_fromUtf8("label"))
label.setText(str(self.vert_layout.indexOf(frame)))
pushButton_2.setText(_translate("MainWindow", "delete this frame and all\n its childs", None))
pushButton_2.mySignal.connect(self.deleteFrame)
def deleteFrame(self,ref):
#finding the index of the FRAME (mybutton's parent)
#that is to be deleted
frame = self.vert_layout.itemAt(self.vert_layout.indexOf(ref.parent()))
widget = frame.widget()
if widget is not None:
widget.deleteLater()
class Main(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
if __name__== '__main__':
app = QtGui.QApplication(sys.argv)
window = Main()
window.show()
sys.exit(app.exec_())

pyqt4 QTableView in QMainWindow with csv input and headers

I am working with a QMainWindow and adding a QTableView widget. The table is to be filled with data from a csv file. The csv file first row has the headers, but I cannot find how to write that row into the headers. Even inputting a test header list does not work.
Also I want to reverse sort on the "time" column.
Here is code restricted to mostly the table:
import sys
import csv
from PyQt4 import QtGui
from PyQt4.QtCore import *
from array import *
class UserWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(UserWindow, self).__init__()
self.specModel = QtGui.QStandardItemModel(self)
self.specList = self.createSpecTable()
self.initUI()
def specData(self):
with open('testFile.csv', 'rb') as csvInput:
for row in csv.reader(csvInput):
if row > 0:
items = [QtGui.QStandardItem(field) for field in row]
self.specModel.appendRow(items)
def createSpecTable(self):
self.specTable = QtGui.QTableView()
# This is a test header - different from what is needed
specHdr = ['Test', 'Date', 'Time', 'Type']
self.specData()
specM = specTableModel(self.specModel, specHdr, self)
self.specTable.setModel(specM)
self.specTable.setShowGrid(False)
vHead = self.specTable.verticalHeader()
vHead.setVisible(False)
hHead = self.specTable.horizontalHeader()
hHead.setStretchLastSection(True)
self.specTable.sortByColumn(3, Qt.DescendingOrder)
return self.specTable
def initUI(self):
self.ctr_frame = QtGui.QWidget()
self.scnBtn = QtGui.QPushButton("Sample")
self.refBtn = QtGui.QPushButton("Reference")
self.stpBtn = QtGui.QPushButton("Blah")
# List Window
self.specList.setModel(self.specModel)
# Layout of Widgets
pGrid = QtGui.QGridLayout()
pGrid.setSpacing(5)
pGrid.addWidget(self.scnBtn, 3, 0, 1, 2)
pGrid.addWidget(self.refBtn, 3, 2, 1, 2)
pGrid.addWidget(self.stpBtn, 3, 4, 1, 2)
pGrid.addWidget(self.specList, 10, 0, 20, 6)
self.ctr_frame.setLayout(pGrid)
self.setCentralWidget(self.ctr_frame)
self.statusBar()
self.setGeometry(300, 300, 400, 300)
self.setWindowTitle('Test')
class specTableModel(QAbstractTableModel):
def __init__(self, datain, headerdata, parent=None, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.arraydata = datain
self.headerdata = headerdata
def rowCount(self, parent):
return len(self.arraydata)
def columnCount(self, parent):
return len(self.arraydata[0])
def data(self, index, role):
if not index.isValid():
return QVariant()
elif role != Qt.DisplayRole:
return QVariant()
return QVariant(self.arraydata[index.row()][index.column()])
def headerData(self, col, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.headerdata[col]
return None
def main():
app = QtGui.QApplication(sys.argv)
app.setStyle(QtGui.QStyleFactory.create("plastique"))
ex = UserWindow()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
and here is a really short csv file:
Run,Date,Time,Comment
data1,03/03/2014,00:04,Reference
data2,03/03/2014,02:00,Reference
data5,03/03/2014,02:08,Sample
data6,03/03/2014,13:57,Sample
Also the rowCount & columnCount definitions do not work.
Worked out answers to what I posted: Wrote a 'getHeader' function simply to read the first line of the csv file and returned the list. Added the following to the createSpecTable function:
specHdr = self.getHeader()
self.specModel.setHorizontalHeaderLabels(specHdr)
self.specModel.sort(2, Qt.DescendingOrder)
The last statement solved the reverse sort problem. The header line from the csv file was removed from the table by adding a last line to the specData function:
self.specModelremoveRow(0).
Finally the rowCount and columnCount were corrected with:
def rowCount(self, parent):
return self.arraydata.rowCount()
def columnCount(self, parent):
return self.arraydata.columnCount()