I have 2 tabs in PyQT5 created as separate classes. 1 class (tab) is to load excel file, second to set rules for removing unneeded rows. When I load file I need to post all headers to QComboBox in other tab so I can create rules. Can't make that to work.
import sys
from PyQt5.QtWidgets import *
import pandas as pd
class BOMAppWindow(QDialog):
def __init__(self):
super().__init__()
self.setGeometry(250, 150, 1400, 600)
mainTabWidget = QTabWidget() # --------- TABS UI ----------
mainTabWidget.addTab(FileOpenTab(), "File Open")
mainTabWidget.addTab(RowRemoveRulesTab(), "Row Delete Rules")
mainVbox = QVBoxLayout()
mainVbox.addWidget(mainTabWidget)
self.setLayout(mainVbox)
df = pd.DataFrame() # pandas dataframe as container for excel spreadsheet
header_list = []
class FileOpenTab(QDialog):
def __init__(self):
super().__init__()
vbox = QVBoxLayout()
h_top_box = QHBoxLayout()
excel_load_button = QPushButton("Open Excel File")
h_top_box.addWidget(excel_load_button) # ---- Adding Widgets to HBox
# ---------------- Adding Table Widget -----------
self.excel_table = QTableWidget()
vbox.addLayout(h_top_box) #-----Create Vertical Box Layout
vbox.addWidget(self.excel_table)
self.setLayout(vbox)
excel_load_button.clicked.connect(self.set_file_data)
# ----------- Open Excel Button Clicked Event
self.show()
def file_path(self): # ----------- file dialog box
filter_excel_only = "Excel Files (*.xlsx)"
filename = QFileDialog.getOpenFileName(self, 'Open Excel File', "", filter_excel_only)
return filename[0]
def set_file_data(self):
path_text = self.file_path()
if path_text:
global df
df = pd.read_excel(path_text, na_filter=False)
self.post_dataframe(df)
RowRemoveRulesTab().update_select_list()
def post_dataframe(self, dataframe):
column_count = dataframe.shape[1]
row_count = dataframe.shape[0]
self.excel_table.setColumnCount(column_count)
self.excel_table.setRowCount(row_count)
self.excel_table.setHorizontalHeaderLabels(list(dataframe.columns))
def header_list(self):
return list(df.columns)
class RowRemoveRulesTab(QDialog):
def __init__(self):
super().__init__()
hbox = QHBoxLayout()
groupBox1 = QGroupBox("Rule 1:")
vbox1 = QVBoxLayout()
self.rule1select = QComboBox()
self.rule1select.addItems(FileOpenTab().header_list())
vbox1.addWidget(self.rule1select)
groupBox1.setLayout(vbox1)
hbox.addWidget(groupBox1)
self.setLayout(hbox)
self.show()
def update_select_list(self):
self.rule1select.clear()
self.rule1select.addItems(FileOpenTab().header_list())
print(FileOpenTab().header_list())
app = QApplication(sys.argv)
bomAppWindow = BOMAppWindow()
bomAppWindow.show()
app.exec()
I need last function in second tab (or any other way to handle it) update_select_list(self): to update QComboBox with header list from excel file loaded in first FileOpenTab class. Now QComboBox remains blank after file load.
The key point of your problem is that you assume that every time you do FileOpenTab() it will always be the same widget but it is not. The same goes for RowRemoveRulesTab. Instead you have to store the object in a variable and reuse it.
On the other hand you have design problems, in this case you must use the Single responsibility principle where it indicates that each class has a function, and must provide methods for other objects to access the information, in Qt/PyQt the simplest way of transmitting information is through signals, in this case when the dataframe is loaded a signal will be emitted with the new headers, and that signal must be connected to a method of the other class so that it updates the information of the QComboBox.
from PyQt5 import QtCore, QtGui, QtWidgets
import pandas as pd
class FileOpenTab(QtWidgets.QWidget):
headersChanged = QtCore.pyqtSignal(list)
def __init__(self, parent=None):
super(FileOpenTab, self).__init__(parent)
excel_load_button = QtWidgets.QPushButton(
"Open Excel File", clicked=self.load_file
)
self.excel_table = QtWidgets.QTableWidget()
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(excel_load_button)
lay.addWidget(self.excel_table)
#QtCore.pyqtSlot()
def load_file(self):
filter_excel_only = "Excel Files (*.xlsx)"
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
self, "Open Excel File", "", filter_excel_only
)
if filename:
df = pd.read_excel(filename, na_filter=False)
self.fill_table(df)
def fill_table(self, dataframe):
row_count, column_count = dataframe.shape
self.excel_table.setColumnCount(column_count)
self.excel_table.setRowCount(row_count)
headers = list(dataframe.columns)
self.excel_table.setHorizontalHeaderLabels(headers)
self.headersChanged.emit(headers)
class RowRemoveRulesTab(QtWidgets.QWidget):
def __init__(self, parent=None):
super(RowRemoveRulesTab, self).__init__(parent)
self.rule_select = QtWidgets.QComboBox()
group_box = QtWidgets.QGroupBox("Rule 1:")
vbox = QtWidgets.QVBoxLayout()
vbox.addWidget(self.rule_select)
group_box.setLayout(vbox)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(group_box)
#QtCore.pyqtSlot(list)
def update_items(self, items):
self.rule_select.clear()
self.rule_select.addItems(items)
class BOMAppWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(BOMAppWindow, self).__init__(parent)
file_open_tab = FileOpenTab()
row_remove_rules_tab = RowRemoveRulesTab()
file_open_tab.headersChanged.connect(row_remove_rules_tab.update_items)
mainTabWidget = QtWidgets.QTabWidget()
mainTabWidget.addTab(file_open_tab, "File Open")
mainTabWidget.addTab(row_remove_rules_tab, "Row Delete Rules")
self.setCentralWidget(mainTabWidget)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = BOMAppWindow()
w.show()
sys.exit(app.exec_())
Related
I am trying to create a tableWidget in PyQt that has copy-paste functionality and the ability to create new tabs. My table is loaded with a initialized sheet but gives the user the ability to create new tabs with new qTableWidgets which I handled using a for loop to create and initialize the widget everytime a new tab is created in my add_sheet() function.
I wanted to also add functionality for copying and pasting inside each tab and across the tabs. Now when I added the key press event function to do this, I kept getting errors when trying to copy and paste in new tabs as out of index. I tried to fix this by keeping a pointer of which tab the selected indexes come from but this only allows me to edit on the first new tab created. The initial spreadsheet crashes when trying to do operations and the other tabs just do not work. It also does not copy and paste universally amongst the tabs.
I feel I have made my handling too complicated and I have a flaw or am missing something in my design pattern.
How can I properly implement my copy-paste function to work amongst all dynamically tabs with their own QTableWidget instances including the initial QTableWidget created both locally and universally?
import sys
from PyQt6.QtWidgets import (QApplication, QMainWindow,
QTableWidget, QTableWidgetItem,QVBoxLayout,QTabWidget,QWidget,QToolButton,QToolBar)
from PyQt6.QtCore import Qt
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.tab_widget = MyTabWidget(self)
self.setCentralWidget(self.tab_widget)
self.initializeUI()
def initializeUI(self):
"""Set up the application's GUI."""
self.setMinimumSize(1200, 500)
self.setWindowTitle("Spreadsheet - QTableWidget Example")
# Used for copy and paste actions
self.item_text = None
self.setUpMainWindow()
self.show()
def setUpMainWindow(self):
"""Create and arrange widgets in the main window."""
# Set initial row and column values
main_spreadsheet_widget.setRowCount(10)
main_spreadsheet_widget.setColumnCount(10)
class MyTabWidget(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
self.layout = QVBoxLayout(self)
# Initialize tab screen
self.sheets = QTabWidget()
self.main_sheet = QWidget()
self.sheets.resize(300, 200)
self.extra_sheets_tracker = list()
self.tab_index = []
self.copied_cells_list = []
self.paste_index = []
# Add sheets
self.sheets.addTab(self.main_sheet, "Main Sheet")
#self.sheets.addTab(self.tab3, "Geeks")
# Create first tab
self.main_sheet.layout = QVBoxLayout(self)
self.main_sheet.layout.addWidget(main_spreadsheet_widget)
self.main_sheet.setLayout(self.main_sheet.layout)
self.tabButton = QToolButton(self)
self.tabButton.setText('+')
font = self.tabButton.font()
font.setBold(True)
self.tabButton.setFont(font)
self.sheets.setCornerWidget(self.tabButton)
self.tabButton.clicked.connect(self.add_sheet)
# Add sheets to widget
self.layout.addWidget(self.sheets)
self.setLayout(self.layout)
def add_sheet(self):
self.sheet = QWidget()
self.main_tab_sheet_widget = QTableWidget()
self.extra_sheets_tracker.append(self.main_tab_sheet_widget)
self.main_tab_sheet_widget.setRowCount(10)
self.main_tab_sheet_widget.setColumnCount(10)
self.sheet.layout = QVBoxLayout(self)
self.sheet.layout.addWidget(self.main_tab_sheet_widget)
self.sheet.setLayout(self.sheet.layout)
self.sheets.addTab(self.main_tab_sheet_widget, "Sheet" + str(len(self.extra_sheets_tracker)))
def keyPressEvent(self, event):
super().keyPressEvent(event)
if event.key() == Qt.Key.Key_C and (event.modifiers() & Qt.KeyboardModifier.ControlModifier):
self.tab_index = []
for i in self.extra_sheets_tracker:
if i.selectedIndexes() is not None:
self.tab_index.append(self.extra_sheets_tracker.index(i))
self.copied_cells = sorted(self.extra_sheets_tracker[self.tab_index[0]].selectedIndexes())
self.copied_cells_list.append(self.copied_cells)
self.copied_cells = None
elif event.key() == Qt.Key.Key_V and (event.modifiers() & Qt.KeyboardModifier.ControlModifier):
self.paste_index = []
for i in self.extra_sheets_tracker:
self.paste_index.append(self.extra_sheets_tracker.index(i))
r = self.extra_sheets_tracker[self.paste_index[0]].currentRow() - self.copied_cells_list[0][0].row()
c = self.extra_sheets_tracker[self.paste_index[0]].currentColumn() - self.copied_cells_list[0][0].column()
for cell in self.copied_cells_list[0]:
self.extra_sheets_tracker[self.paste_index[0]].setItem(cell.row() + r, cell.column() + c, QTableWidgetItem(cell.data()))
if __name__ == "__main__":
app = QApplication(sys.argv)
main_spreadsheet_widget = QTableWidget()
window = MainWindow()
window.show()
sys.exit(app.exec())
I have managed to do the following:
1- I treated the main sheet as if it was "just another sheet" and made sure it follows the same relative routine. This included removing unnecessary functions like setUpMainWindow and introducing static values like MAX_ROWS and MAX_COLS for maximum rows and columns respectively. This also entailed renaming extra_sheets_tracker to become sheets_tracker since it will hold all of the sheets.
2- I have created two strategies for pasting: 1st-cell for selecting the first cell in a table, or 1-to-1 for selecting the exact count of cells at the pasting side. This meant, also, checking for the dimensions beforehand and raising the exception Unmatching pasting size if the sizes did not match.
3- I removed self.tab_index and self.copied_cells_list since they are not used. copy_list is used globally and it is not a bad idea to stay in self. However paste_list is not used anywhere else than the paste routine and I removed it from self. You need to look into your self variables, you seem to overuse them.
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidget, QTableWidgetItem, QVBoxLayout, QTabWidget, QWidget, QToolButton, QToolBar
from PyQt6.QtCore import Qt
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.tab_widget = MyTabWidget(self)
self.setCentralWidget(self.tab_widget)
self.initializeUI()
def initializeUI(self):
"""Set up the application's GUI."""
self.setMinimumSize(1200, 500)
self.setWindowTitle("Spreadsheet - QTableWidget Example")
# Used for copy and paste actions
self.item_text = None
self.show()
class MyTabWidget(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
self.layout = QVBoxLayout(self)
# Initialize tab screen
self.MAX_ROWS = 10
self.MAX_COLS = 10
self.STRATEGY = {0:'1st-cell', 1:'1-to-1'}
self.sheets = QTabWidget()
self.main_sheet = QWidget()
self.sheets.resize(300, 200)
self.sheets_tracker = list()
self.copy_list = []
#self.copied_cells_list = []
#self.paste_list = []
# Add a sheet and create first tab
self.main_sheet.layout = QVBoxLayout(self)
# Setup main window
self.add_sheet()
tabButton = QToolButton(self)
tabButton.setText('+')
font = tabButton.font()
font.setBold(True)
tabButton.setFont(font)
tabButton.clicked.connect(self.add_sheet)
self.sheets.setCornerWidget(tabButton)
# Add sheets to widget
self.layout.addWidget(self.sheets)
self.setLayout(self.layout)
def add_sheet(self):
sheets_count = len(self.sheets_tracker)
if sheets_count < 1:
label = "Main sheet"
else:
label = f"Sheet{sheets_count}"
self.main_tab_sheet_widget = QTableWidget()
self.main_tab_sheet_widget.setRowCount(self.MAX_ROWS)
self.main_tab_sheet_widget.setColumnCount(self.MAX_COLS)
self.sheets_tracker.append(self.main_tab_sheet_widget)
self.sheet = QWidget()
self.sheet.layout = QVBoxLayout(self)
self.sheet.layout.addWidget(self.main_tab_sheet_widget)
self.sheet.setLayout(self.sheet.layout)
self.sheets.addTab(self.main_tab_sheet_widget, label)
def keyPressEvent(self, event):
super().keyPressEvent(event)
if event.key() == Qt.Key.Key_C and (event.modifiers() & Qt.KeyboardModifier.ControlModifier):
self.copy_list = sorted([(e.row(), e.column(), e.data()) for e in self.sheets_tracker[self.sheets.currentIndex()].selectedIndexes()])
if len(self.copy_list) != 0:
# recalculate the indicies to absolute values
least_row = self.copy_list[0][0]
least_col = sorted(self.copy_list, key=lambda tup: tup[1])[0][1]
self.copy_list = [(e[0]-least_row, e[1]-least_col, e[2]) for e in self.copy_list]
print(self.copy_list)
elif event.key() == Qt.Key.Key_V and (event.modifiers() & Qt.KeyboardModifier.ControlModifier):
paste_list = sorted([(element.row(), element.column(), element.data()) for element in self.sheets_tracker[self.sheets.currentIndex()].selectedIndexes()])
if len(paste_list) != 0:
if len(paste_list) == 1:
# The given paste position is the first cell only
current_r, current_c, _ = paste_list[-1]
last_r, last_c, _ = self.copy_list[-1]
if last_r + current_r - 1 < self.MAX_ROWS and last_c + current_c - 1 < self.MAX_COLS:
strategy = self.STRATEGY[0]
else:
raise Exception('Unmatching pasting size')
elif len(self.copy_list) == len(paste_list):
# You can paste in one-to-one correspondence
strategy = self.STRATEGY[1]
else:
raise Exception('Unmatching pasting size')
if strategy == self.STRATEGY[0]:
r, c, _ = paste_list[0]
for index, e in enumerate(self.copy_list):
_, _, d = self.copy_list[index]
d = '' if d is None else d
print(f"Pasting at index [{self.sheets.currentIndex()}] cell ({e[0]+r}, {e[1]+c})")
textCell = QTableWidgetItem(); textCell.setText(f'{d}')
self.sheets_tracker[self.sheets.currentIndex()].setItem(e[0]+r, e[1]+c, textCell)
if strategy == self.STRATEGY[1]:
for index, e in enumerate(paste_list):
_, _, d = self.copy_list[index]
d = '' if d is None else d
print(f"Pasting at index [{self.sheets.currentIndex()}] cell ({e[0]}, {e[1]})")
textCell = QTableWidgetItem(); textCell.setText(f'{d}')
self.sheets_tracker[self.sheets.currentIndex()].setItem(e[0], e[1], textCell)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
I want to use QtreeView to organize the data shown by a QComboBox. As you can see in my example, creating the box and setting up data works so far.
But my problem is, that the combobox itself only shows the first argument and not the whole line. what I want to have is, that there is shown the whole row, not only the first item of the row.
Is this maybe related to the fact, that each cell is selectable? Do I have to prohibit to select items at the end of the tree branch?
How can I achieve this while adding the elements to the QtreeView-data?
minimal example:
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
data = [['a','b','c'],['d','e','f'],['g','h','i']]
class MainWindow(QMainWindow):
dispatcher = 0
def __init__(self):
super().__init__()
# buil UI
self.init_ui()
def init_ui(self):
# layout
self.box_window = QVBoxLayout()
# content
model = QStandardItemModel(len(data),len(data[0]))
row = 0
for r in data:
col = 0
for item in r:
model.setData(model.index(row, col), item)
col += 1
row += 1
tree_view = QTreeView()
tree_view.setHeaderHidden(True)
tree_view.setRootIsDecorated(False)
tree_view.setAlternatingRowColors(True)
combobox = QComboBox()
combobox.setMinimumSize(250,50)
combobox.setView(tree_view)
combobox.setModel(model)
self.box_window.addWidget(combobox)
self.box_window.addStretch()
# build central widget and select it
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.centralWidget().setLayout(self.box_window)
# show window
self.setGeometry(50,50,1024,768)
self.setWindowTitle("Test")
self.show()
def main():
app = QApplication(sys.argv)
main_window = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
A possible solution is to concatenate the texts in the row and set as the text to be painted:
class ComboBox(QComboBox):
def paintEvent(self, event):
painter = QStylePainter(self)
painter.setPen(self.palette().color(QPalette.Text))
# draw the combobox frame, focusrect and selected etc.
opt = QStyleOptionComboBox()
self.initStyleOption(opt)
values = []
for c in range(self.model().columnCount()):
index = self.model().index(self.currentIndex(), c, self.rootModelIndex())
values.append(index.data())
opt.currentText = " ".join(values)
painter.drawComplexControl(QStyle.CC_ComboBox, opt)
# draw the icon and text
painter.drawControl(QStyle.CE_ComboBoxLabel, opt)
I want to add widgets in GUI when a user selects a particular item from QComboBox.
With the different options in combo-box Pip config, I want GUI to look like as in the following images. In the right image, there are extra widgets present for an item Multi pip. Also I want the location of the extra widgets as shown in the right image.
How to add these widgets dynamically ? Please find the code below.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import Qt, QRect
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
vbox = QVBoxLayout()
CpsLabel = QLabel()
CpsLabel.setText("<font size = 12>Cps</font>")
CpsLabel.setAlignment(Qt.AlignCenter)
CpsLabel.setTextFormat(Qt.RichText)
CpsPipConfigLabel = QLabel('Pip config: ')
CpsPipConfigComboBox = QComboBox()
CpsPipConfigComboBox.addItems(['Single pip', 'Dual pip', 'Multi pip'])
CpsPipConfigComboBox.setCurrentIndex(2)
CpsChannel = QLabel('Cps channel: ')
CpsChannelComboBox = QComboBox()
CpsChannelComboBox.addItems(['A', 'B', 'C', 'D'])
CpsChannelComboBox.setCurrentIndex(0)
CpsTotalTeethLabel = QLabel('Total teeth: ')
CpsTotalTeethEdit = QLineEdit()
CpsTotalTeethEdit.setFixedWidth(50)
CpsTotalTeethEdit.setPlaceholderText('18')
CpsTotalTeethEdit.setValidator(QIntValidator())
CpsMissingTeethLabel = QLabel('Missing teeth: ')
CpsMissingTeethEdit = QLineEdit()
CpsMissingTeethEdit.setFixedWidth(50)
CpsMissingTeethEdit.setPlaceholderText('1')
CpsMissingTeethEdit.setValidator(QIntValidator())
vbox.addWidget(CpsLabel)
vbox.addStretch()
CpsQHBox1 = QHBoxLayout()
CpsQHBox1.setSpacing(0)
CpsQHBox1.addStretch()
CpsQHBox1.addWidget(CpsPipConfigLabel)
CpsQHBox1.addWidget(CpsPipConfigComboBox)
CpsQHBox1.addStretch()
vbox.addLayout(CpsQHBox1)
vbox.addStretch()
CpsQHBox2 = QHBoxLayout()
CpsQHBox2.setSpacing(0)
CpsQHBox2.addStretch()
CpsQHBox2.addSpacing(20)
CpsQHBox2.addWidget(CpsTotalTeethLabel)
CpsQHBox2.addWidget(CpsTotalTeethEdit)
CpsQHBox2.addStretch()
CpsQHBox2.addWidget(CpsMissingTeethLabel)
CpsQHBox2.addWidget(CpsMissingTeethEdit)
CpsQHBox2.addStretch()
vbox.addLayout(CpsQHBox2)
vbox.addStretch()
CpsQHBox3 = QHBoxLayout()
CpsQHBox3.setSpacing(0)
CpsQHBox3.addStretch()
CpsQHBox3.addWidget(CpsChannel)
CpsQHBox3.addWidget(CpsChannelComboBox)
CpsQHBox3.addStretch()
vbox.addLayout(CpsQHBox3)
vbox.addStretch()
self.setLayout(vbox)
self.setGeometry(200, 100, 300, 300)
self.setWindowTitle('Steady state data processing')
self.setWindowIcon(QIcon('duty_vs_suction_map_sum.png'))
self.setAutoFillBackground(True)
p = self.palette()
p.setColor(self.backgroundRole(), QColor(255,250,100))
# p.setColor(self.backgroundRole(), Qt.blue)
self.setPalette(p)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
I suggest you set the widgets up and place them at the beginning like you have them, but set them invisible. Then make a method that sets the appropriate widgets visible based on the qcombobox's current text and connect it to the qcombobox's activated signal.
You will also need to add self in front of almost every object so that it can be referred to from other methods.
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
# setup code here...
self.CpsTotalTeethEdit.setVisible(False)
self.CpsTotalTeethLabel.setVisible(False)
self.CpsPipConfigComboBox.activated.connect(self.setup_total_teeth)
self.show()
def setup_widgets(self):
if self.CpsPipConfigComboBox.currentText() == "Multi pip":
self.CpsTotalTeethLabel.setVisible(True)
self.CpsTotalTeethEdit.setVisible(True)
By setting the items invisible instead of adding them with this method, you can also set them to be not visible when the cobobox's position is not for them.
I have a list which gets one element each time user opens a file. I need to create a button with the file's name (element from the list), each time this file is appended to a list, and put this button into a scroll-area.
The problem is that I always have only one button, that just changes its name:
filenames = []
def addfiles():
fileName = QtGui.QFileDialog.getOpenFileName()
fileDirectory = unicode(fileName)
global filenames
filenames.append(fileDirectory)
button = QtGui.QPushButton(os.path.basename(fileDirectory))
window.scrollArea.setWidget(button)
I know that the problem is that I add the same object (button) to the scroll-area, but I don't know how to fix it.
The Problem is not that you add the same button, but that you sort of replace the Widget in the scrollArea.
A better way would be to create a QHBoxLayout and than add the buttons to the layout.
filenames = []
lay = QtGui.QHboxLayout()
window.scrollArea.setLayout(lay)
def addfiles():
fileName= QtGui.QFileDialog.getOpenFileName()
fileDirectory = unicode(fileName)
global filenames
filenames.append(fileDirectory)
button = QtGui.QPushButton(os.path.basename(fileDirectory))
lay.addWidget(button)
In a sort of that way it should work. Here is a small working example:
from PyQt4 import QtGui
import sys
filenames = []
class TestGui(QtGui.QWidget):
""" A Fast test gui show how to create buttons in a ScrollArea"""
def __init__(self):
super(TestGui, self).__init__()
self.lay = QtGui.QHBoxLayout()
self.sA = QtGui.QScrollArea()
self.sA_lay = QtGui.QVBoxLayout()
self.sA.setLayout(self.sA_lay)
self.closeGui = QtGui.QPushButton("Close")
self.add_file_button = QtGui.QPushButton("Add File")
self.lay.addWidget(self.closeGui)
self.lay.addWidget(self.add_file_button)
self.lay.addWidget(self.sA)
self.setLayout(self.lay)
self.connect_()
self.show()
def connect_(self):
self.add_file_button.clicked.connect(self.__add_file_to_list)
self.closeGui.clicked.connect(self.close)
return
def __add_file_to_list(self):
fname = QtGui.QFileDialog.getOpenFileName()
global filenames
filenames.append(fname)
button = QtGui.QPushButton(fname)
self.sA_lay.addWidget(button)
return
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
tg = TestGui()
sys.exit(app.exec_())
The problem is that you're not adding a layout to the scrollLayout, you're setting the scrollArea's widget:
#!/usr/bin/env python
import os, sys
from PyQt4 import QtCore, QtGui
filenames = []
class Window(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.centralwidget = QtGui.QWidget(self)
self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget)
self.scrollArea = QtGui.QScrollArea(self.centralwidget)
self.scrollArea.setWidgetResizable(True)
self.scrollAreaWidgetContents = QtGui.QWidget(self.scrollArea)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.verticalLayout.addWidget(self.scrollArea)
self.setCentralWidget(self.centralwidget)
# create a layout for your scrollarea
self.formLayout = QtGui.QFormLayout(self.scrollAreaWidgetContents)
self.addFiles()
def addFiles(self):
global filenames
filenames.append("~/files/newFile.txt")
button = QtGui.QPushButton(os.path.basename(filenames[-1]))
self.formLayout.addWidget(button)
I'm trying to populate a QTableWidget with the attributes of a file opened elsewhere in the script. I've successfully set the file attributes read in from the file using the following code:
class FileHeader(object):
fileheader_fields=(
"filetype","fileversion","numframes",
"framerate","resolution","numbeams",
"samplerate","samplesperchannel","receivergain",
"windowstart","winlengthsindex","reverse",
"serialnumber","date","idstring","ID1","ID2",
"ID3","ID4","framestart","frameend","timelapse",
"recordInterval","radioseconds","frameinterval","userassigned")
fileheader_formats=(
'S3','B','i4','i4','i4','i4','f','i4','i4','i4',
'i4','i4','i4','S32','S256','i4','i4','i4','i4',
'i4','i4','i4','i4','i4','i4','S136')
IMAGE_HEADER_BYTES = 256
IMAGES_DATA_BYTES = 49152
def __init__(self,filename=''):
self.filename = filename
if filename:
self.setFile(filename)
else:
# initialize our attributes to None
for field in self.fileheader_fields:
setattr(self,field,None)
def setFile(self, f):
self.infile=open(f, 'rb')
dtype=dict(names=self.fileheader_fields, formats=self.fileheader_formats)
self.fileheader=np.fromfile(self.infile, dtype=dtype, count=1)
self.fileheader_length=self.infile.tell()
for field in self.fileheader_fields:
setattr(self,field,self.fileheader[field])
I've used this code to populate the table but I keep getting a "FileHeader has no attribute fileheader" error.
from fileheader import FileHeader, Frame
from echogram import QEchogram
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import os, sys
class MainWindow(QWidget):
def __init__(self, parent=None):
self.fileheader_fields=FileHeader.fileheader_fields
self.fileheader_values=FileHeader.fileheader[field]
self.fileheader={field: "value of" + field
for field in self.fileheader_fields}
super(MainWindow, self).__init__(parent)
self.fileheader_table=QTableWidget()
layout=QVBoxLayout()
layout.addWidget(self.fileheader_table)
self.setLayout(layout)
self.populate
def populate(self):
self.fileheader_table.setRowCount(len(self.fileheader_fields))
self.fileheader_table.sestColumnCount(2)
self.fileheader_table.setHorizontalHeaderLabels(['name','value'])
for i,field in enumerate(self.fileheader_fields):
name=QTableWidgetItem(field)
value=QTableWidgetItem(self.fileheader[field])
self.fileheader_table.setItem(i,0,name)
self.fileheader_table.setItem(i,1,value)
if __name__=="__main__":
app=QApplication(sys.argv)
filename=str(QFileDialog.getOpenFileName(None,"open file","C:/vprice/DIDSON/DIDSON Data","*.ddf"))
wnd=MainWindow()
wnd.resize(640,480)
wnd.show()
#echoGram=QEchogram()
#echoGram.initFromFile(filename)
#fileName="test.png"
#echoGram.processEchogram()
#dataH=echoGram.data
#print "Horizontal data", dataH
Bear with me-- I just started with all of the Python stuff about a month ago...
See populate method. Also there is some examples in documentation
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
self.fileheader_fields=(
"filetype","fileversion","numframes",
"framerate","resolution","numbeams",
"samplerate","samplesperchannel","receivergain",
"windowstart","winlengthsindex","reverse",
"serialnumber","date","idstring","ID1","ID2",
"ID3","ID4","framestart","frameend","timelapse",
"recordInterval","radioseconds","frameinterval","userassigned"
)
# just for test
self.fileheader = {field: 'value of ' + field
for field in self.fileheader_fields}
super(MainWindow, self).__init__(parent)
self.table_widget = QtGui.QTableWidget()
layout = QtGui.QVBoxLayout()
layout.addWidget(self.table_widget)
self.setLayout(layout)
self.populate()
def populate(self):
self.table_widget.setRowCount(len(self.fileheader_fields))
self.table_widget.setColumnCount(2)
self.table_widget.setHorizontalHeaderLabels(['name', 'value'])
for i, field in enumerate(self.fileheader_fields):
name = QtGui.QTableWidgetItem(field)
value = QtGui.QTableWidgetItem(self.fileheader[field])
self.table_widget.setItem(i, 0, name)
self.table_widget.setItem(i, 1, value)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
wnd = MainWindow()
wnd.resize(640, 480)
wnd.show()
sys.exit(app.exec_())
UPD
Code for your concrete case:
from fileheader import FileHeader, Frame
from echogram import QEchogram
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import os, sys
class MainWindow(QWidget):
def __init__(self, filename, parent=None):
super(MainWindow, self).__init__(parent)
# here we are loading file
# now self.fileheader contains attributes
self.fileheader = FileHeader(filename)
self.fileheader_table = QTableWidget()
layout = QVBoxLayout()
layout.addWidget(self.fileheader_table)
self.setLayout(layout)
self.populate()
def populate(self):
self.fileheader_table.setRowCount(len(self.fileheader.fileheader_fields))
self.fileheader_table.sestColumnCount(2)
self.fileheader_table.setHorizontalHeaderLabels(['name','value'])
for i,field in enumerate(self.fileheader.fileheader_fields):
name=QTableWidgetItem(field)
value=QTableWidgetItem(getattr(self.fileheader, field))
self.fileheader_table.setItem(i,0,name)
self.fileheader_table.setItem(i,1,value)
if __name__=="__main__":
app=QApplication(sys.argv)
filename=str(QFileDialog.getOpenFileName(None,"open file","C:/vprice/DIDSON/DIDSON Data","*.ddf"))
wnd=MainWindow(filename)
wnd.resize(640,480)
wnd.show()
#echoGram=QEchogram()
#echoGram.initFromFile(filename)
#fileName="test.png"
#echoGram.processEchogram()
#dataH=echoGram.data
#print "Horizontal data", dataH
ok u have to add a QTableWidget to your custom QtGui.QMainWindow
i would create i whith 0 line and the right amount of collumn,like this:
self.tableArea=QtGui.QTableWidget(0,self.fileheader_length,self)
self.setHorizontalHeaderLabels(['nameOne','nameTwo'])#will name your top header
self.verticalHeader().setVisible(False)#will hide your left header if you don't need them
and add your line one by one
self.tableArea.insertRow(row)#it will add a line at the row position
after that u have to create a QTableWidgetItem for each cell
itemTo=QtGui.QTableWidgetItem('text')#replace text by your value
and place your item in the cell you want
self.tableArea.setItem(row, column, itemTo)