I need bit of assistance with my python code. I am a newbie to python so not very good at it.
I have an excel spreadsheet with a bunch of lecture times and I am using the code below;
df = pd.read_excel('/home/pi/timetable1.xlsx')
df['Date'] = pd.to_datetime(df['Date']).dt.strftime("%d-%m-%Y")
now = pd.to_datetime('today').strftime("%d-%m-%Y")
print(df[df['Date'] == now])
which displays a simple line of timetable text such as below [xx:xx is time in 24 hr format];
Lesson 1: Lesson 2: Lesson 3: Lession 4: Lesson 5:
xx:xx xx:xx xx:xx xx:xx xx:xx
I have configured it so that the above displayed times only shows the times for the "Current Date".
What I am trying to acheive is that I want to use PyQt4 to display this information on a graphical window.
So for example, the below displays "HELLO WORLD" text in the gui window;
def wxfinished():
attribution3.setText("HELLO WORLD")
attribution3 = QtGui.QLabel(foreGround)
attribution3.setObjectName("attribution3")
attribution3.setStyleSheet("#attribution3 { " +
"background-color: transparent; color: " +
Config.textcolor +
"; font-size: " +
str(int(50 * xscale)) + #50 is the size of the text
"px; " +
Config.fontattr +
"}")
attribution3.setAlignment(Qt.AlignTop)
attribution3.setGeometry(450 * xscale, 670 * yscale, 1000 * xscale, 1000)
w.show()
w.showFullScreen()
sys.exit(app.exec_())
How can I change it so that instead of "HELLO WORLD" I can print out the timetable output?
While I'm not that familiar with Pandas, here's an MRE to help you. In this, a table is made, the labels are set to the excel's labels (lesson x), and the singular row is filled out with the dates.
from PyQt4.QtGui import QApplication, QTableWidget, QLabel, QFont
from PyQt4.QtCore import Qt
import sys
import pandas
CELL_FONT = QFont()
CELL_FONT.setPointSize(8)
def getLessions(): # assuming the code you provided works
"""
Returns Pandas DataFrame object w/ today's date info
:return:
"""
data = pandas.read_excel("path")
date = pandas.to_datatime(data["Date"]).dtftime("%d-%m-%Y")
now = pandas.to_datetime('today').strftime("%d-%m-%Y")
return data[date == now]
def makeWidget():
datum = getLessions()
columns = len(datum.columns)
# Use table to display information
table = QTableWidget()
table.setRowCount(1)
table.setColumnCount(columns)
table.setHorizontalHeaderLabels(datum.columns) # I think datum.columns returns [str], I could be wrong
table.setVerticalHeaderLabels([""])
# Row will be filled with Labels w/ times
for i in range(columns):
lession_time = str(datum.iloc[0,i]) # edit: iloc returns a Timestamp object
label = QLabel()
label.setFont(CELL_FONT)
label.setText(lession_time)
label.setAlignment(Qt.AlignHCenter | Qt.AlignBottom)
table.setCellWidget(0, i, label)
return table
def makeWidgetDummy(): # Doesn't use Pandas
columns = 5
table = QTableWidget()
table.setRowCount(1)
table.setColumnCount(columns)
horizontal_lbls = ["Lesson {}".format(i + 1) for i in range(columns)]
table.setHorizontalHeaderLabels(horizontal_lbls)
table.setVerticalHeaderLabels([""])
for i in range(columns):
lession_time = "XX:XX"
label = QLabel()
label.setFont(CELL_FONT)
label.setText(lession_time)
label.setAlignment(Qt.AlignHCenter | Qt.AlignBottom)
table.setCellWidget(0, i, label)
def main():
app = QApplication(sys.argv)
widget = makeWidget()
# widget = makeWidgetDummy()
widget.show()
app.exec_()
if __name__ == "__main__":
main()
Related
Basically, I have a QTableView and the last column of each row contains a QMenu where if triggered, the row should be deleted. I tried the code below, but if I click on the menu that is in a row number > 1, the returned rowNum is -1:
Code:
def addrowIntable(self, a, b):
Column1 = QStandardItem("%s" % (a))
Column2 = QStandardItem("%s" % (b))
actionBTN = QPushButton("")
actionMenu = QMenu()
self.RemList = QtWidgets.QAction("Remove row", actionMenu)
actionMenu.addAction(self.RemList)
actionMenu.raise_()
actionBTN.setMenu(actionMenu)
self.rulesWhitelistWidgetModel.appendRow([Column1, Column2])
self.rulesWhiteListFileTBL.setIndexWidget(
self.rulesWhitelistWidgetModel.index(self.rulesWhitelistWidgetModel.rowCount() - 1,
self.rulesWhiteListFileTBL.model().columnCount() - 1), actionBTN)
self.RemList.triggered.connect(lambda: self.deleteRow("Hello"))
def deleteRow(self, str):
rowNum = self.rulesWhiteListFileTBL.rowAt(self.rulesWhiteListFileTBL.viewport().mapFromGlobal(self.sender().parent().pos()).y())
print(self.rulesWhiteListFileTBL.indexAt(self.sender().parent().pos()).row())
print(rowNum)
I just need to know which row number was the sender from inside deleteRow where I could then use model.removeRow() to delete it.
The main reason why your code doesn't work as expected is because you set the menu as the parent of the action. A menu is a popup window, so its position will be in global coordinates, whereas you want the position relative to the table. A simple way to achieve this is to make the button the parent of the action instead.
The following revision of your code should do what you want:
def addrowIntable(self, a, b):
Column1 = QStandardItem("%s" % (a))
Column2 = QStandardItem("%s" % (b))
actionBTN = QPushButton()
actionMenu = QMenu()
actionRem = QtWidgets.QAction("Remove row", actionBTN)
actionMenu.addAction(actionRem)
actionBTN.setMenu(actionMenu)
self.rulesWhitelistWidgetModel.appendRow([Column1, Column2])
self.rulesWhiteListFileTBL.setIndexWidget(Column2.index(), actionBTN)
actionRem.triggered.connect(lambda: self.deleteRow("Hello"))
def deleteRow(self, str):
pos = self.sender().parent().pos()
index = self.rulesWhiteListFileTBL.indexAt(pos)
self.rulesWhitelistWidgetModel.removeRow(index.row())
I'm trying to make a widget with multiple tabs that are occupied with different excel tables per tab and can't figure why I cant populate each tab separately.
About the tables the number of columns remain the same for all Excel tables only the number of rows change.
import sys
from PyQt5 import QtCore , QtWidgets ,QtGui
import pandas as pd
import os
class MyApp(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.sizeHint().width(), self.sizeHint().height()
self.resize(self.width(), self.height())
layout = QtWidgets.QVBoxLayout()
self.setLayout(layout)
self.table = QtWidgets.QTableWidget()
self.tabs = QtWidgets.QTabWidget()
self.table.setSortingEnabled(True)
self.table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.table.selectionModel().selectionChanged.connect(self.selected)
# self.add_flight_tab()
layout.addWidget(self.tabs)
tab_list = self.add_flight_tab(path_xl)
for tables , names in zip(range(tab_list.__sizeof__()), tab_list):
self.tabs.setCurrentIndex(tables)
self.load_data(f"{path_xl}/{names}")
self.setLayout(layout)
def load_data(self, path_to_xl):
df = pd.read_excel(path_to_xl,sheet_name=0, usecols=["AWB", "Destn.", "SCC", "Agent Name",
"Stated Pcs/Wgt/Vol (kg/CBM)","Booked Flight"])
if df.size == 0:
return
df.fillna('', inplace=True)
self.table.setRowCount(df.shape[0])
self.table.setColumnCount(df.shape[1])
self.table.setHorizontalHeaderLabels(df.columns)
self.table.insertColumn(self.table.columnCount())
self.table.setHorizontalHeaderItem(6 , QtWidgets.QTableWidgetItem("Offload"))
self.table.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
for row in df.iterrows():
values = row[1]
for i in range(df.shape[0]):
check_box = QtWidgets.QTableWidgetItem()
check_box.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
check_box.setCheckState(QtCore.Qt.CheckState())
self.table.setItem(i, 6, check_box)
for col_index, value in enumerate(values):
if isinstance(value, (float, int)):
value = '{0:0,.0f}'.format(value)
tableItem = QtWidgets.QTableWidgetItem(str(value))
self.table.setItem(row[0], col_index, tableItem)
def add_flight_tab(self, path_files):
files = os.listdir(path_files)
new_ls = []
for xl, tab_ind in zip(files, range(files.__sizeof__())):
if xl.endswith(".xlsx") or xl.endswith(".XLSX"):
new_ls.append(xl)
self.tabs.insertTab(tab_ind,QtWidgets.QTableWidget(), xl)
self.tabs.setCurrentIndex(tab_ind)
return new_ls
if __name__ == '__main__':
path_xl = "path to excel"
app = QtWidgets.QApplication(sys.argv)
myApp = MyApp()
myApp.show()
# print(myApp.add_flight_tab())
try:
sys.exit(app.exec_())
except SystemExit:
print("Closing window...")
Everything I have tried gives two results(there must be something I'm missing out in here) :
The Widget is populated but the are no other tabs only thing changed is the following lines:
layout.addWidget(self.tabs)
tab_list = self.add_flight_tab(path_xl)
for tables , names in zip(range(tab_list.__sizeof__()), tab_list):
self.tabs.setCurrentIndex(tables)
self.load_data(f"{path_xl}/{names}")
layout.addChildWidget(self.table)
For now the names of the tabs is irrelevant , I only need to have number of tabs according to number of Excel files and each tab is filled with table accordingly.
I am making a physics calculator that takes values from the person and uses a calculation to show the answer. the problem is that when i press submit to take the values and save them as variable and show a button to show the answer, the app closes and sublime text shows REPL closed. i have no idea why. please help. i think the problem is in f2(). thank you for your patience.
import sys
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QToolTip , QCheckBox, QLCDNumber,QLineEdit,QInputDialog#just compile the modules like this
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QLabel
def ObjectDensity():
dflabel = QLabel("Please Enter Density of Fluid: ",w)
dflabel.move(25,220)
dflabel.show()
dfte = QLineEdit(w)
dfte.move(25,260)
dfte.show()
Weight2 = QLabel("Please Enter Weight:",w)
Weight2.move(25,300)
Weight2.show()
Wte = QLineEdit(w)
Wte.move(25,340)
Wte.show()
AIW2 = QLabel("Enter Apperent Immersed Weight: ",w)
AIW2.move(25,380)
AIW2.show()
aiwte = QLineEdit(w)
aiwte.move(25,420)
aiwte.show()
ansbutton = QPushButton("Submit",w)
ansbutton.move(50,480)
ansbutton.show()
ansbutton.clicked.connect(lambda: f1(dfte,Wte,aiwte,ansdo))
# df1 = dfte.text()
# w2 = Wte.text()
# aiw6 = aiwte.text()
def f1(dfte,Wte,aiwte,ansdo):
df1 = int(dfte.text())
w2 = int(Wte.text())
aiw6 = int(aiwte.text())
# ansdo = ((w2/w2-aiw6)*df1)
# ans4 = int(ansdo)
ans = QPushButton("press to show answer",w)
ans.move(50,250)
ans.show()
ans.clicked.connect(lambda:f2(w2,aiw6,df1))
def f2(w2,aiw6,df1):
ansdo = ((w2/w2-aiw6)*df1)
ans4 = int(ansdo)
answer = QLabel(ans4,w)
answer.move(75,300)
answer.show()
def arch():
l_archimedes = QLabel("Archimedes' Law",w)
l_archimedes.move(25,80)
l_archimedes.show()
l_archimedes2 = QLabel("Density of Object/Density of Fluid = Weight/(Weight - Apparent Immersed Weight)",w)
l_archimedes2.move(25,110)
l_archimedes2.show()
Archimedeslaw = QLabel("What Do You Want to Solve For:",w)
Archimedeslaw.move(25,145)
Archimedeslaw.show()
dop = QPushButton("Density of Object",w)
dop.move(25,160)
dop.show()
dop.clicked.connect(ObjectDensity)
DF = QPushButton("Density of Fluid",w)
DF.move(200,160)
DF.show()
Weight = QPushButton("Weight",w)
Weight.move(375,160)
Weight.show()
AIW = QPushButton("Apperent Immersed Weight",w)
AIW.move(500,160)
AIW.show()
app = QApplication(sys.argv)
w = QWidget()
w.resize(900,600)
w.move(460,0)
w.setWindowTitle("Physics Laws")
L1 = QLabel("Welcome To Physics Laws",w,)
L1.move(25,0)
b1 = QPushButton("Archimedes Law",w)
b1.move(25,45)
b1.clicked.connect(arch)
w. show()
sys.exit(app.exec_())
If I search for letter x forward (button Next), everything works as it should, but as soon as I change direction (button Previous), this happens:
QsciScintilla.findFirst() doesn't move selection. I.e., first press of button Previous doesn't do anything;
QsciScintilla.findNext() moves in steps of 2, thus skipping one character.
ATM I'm considering translating logic for find operations from C++ to Python, thus potentially fixing the issue, but it'd be nice to know that I made some novice mistake, thus avoiding all the extra work...
Here's the code:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.Qsci import *
import sys
class FindAndReplace(QWidget):
def __init__(self, *arg, **kwarg):
super(self.__class__, self).__init__(*arg, **kwarg)
rows = QVBoxLayout()
self.editor = QsciScintilla()
self.editor.setText(f'{"x"*40}\n{"y"*40}\n{"z"*40}\n')
rows.addWidget(self.editor)
self.text_to_find = ''
self.state_ = tuple()
self.find = QLineEdit()
self.find_previous = QPushButton('&Previous')
self.find_next = QPushButton('&Next')
self.find_lbl = QLabel('&Find')
self.find_lbl.setBuddy(self.find)
row = QHBoxLayout()
for w in (self.find_lbl, self.find, self.find_previous, self.find_next):
row.addWidget(w)
rows.addLayout(row)
self.re = QCheckBox('&Regular expressions')
self.cs = QCheckBox('&Case sensitive')
self.wo = QCheckBox('Whole &words')
self.wrap = QCheckBox('Wrap aroun&d')
self.show_ = QCheckBox('&Unfold folded text')
self.posix = QCheckBox('POSI&X-compatible RE')
row = QHBoxLayout()
for w in (self.re, self.cs, self.wo, self.wrap, self.show_, self.posix):
row.addWidget(w)
rows.addLayout(row)
self.setLayout(rows)
self.find_previous.clicked.connect(lambda: self.findText(forward = False))
self.find_next.clicked.connect(lambda: self.findText(forward = True))
def findText(self, forward):
text_to_find = self.find.text()
state_ = ( \
self.re.isChecked(), self.cs.isChecked(),
self.wo.isChecked(), self.wrap.isChecked(),
forward, -1, -1,
self.show_.isChecked(), self.posix.isChecked(),
)
if text_to_find != self.text_to_find or state_ != self.state_:
self.text_to_find = text_to_find
self.state_ = state_
# search with new conditions.
self.editor.findFirst(text_to_find, *state_)
else:
# search with previously set conditions.
self.editor.findNext()
if __name__ == '__main__':
app = QApplication(sys.argv)
FindAndReplace().show()
sys.exit(app.exec_())
The findNext function looks buggy to me. If I use getSelection to explicitly enter line and index in findFirst, and avoid using findNext altogether, everything works as expected:
def findText(self, forward):
text_to_find = self.find.text()
if forward:
line, index = self.editor.getSelection()[2:]
else:
line, index = self.editor.getSelection()[:2]
state_ = (
self.re.isChecked(), self.cs.isChecked(),
self.wo.isChecked(), self.wrap.isChecked(),
forward, line, index,
self.show_.isChecked(), self.posix.isChecked(),
)
self.text_to_find = text_to_find
self.state_ = state_
self.editor.findFirst(text_to_find, *state_)
Looking at the latest source code (qsciscintilla.cpp, line 1853) I see this:
// Finally adjust the start position so that we don't find the same one again.
if (findState.forward)
findState.startpos = targend;
else if ((findState.startpos = targstart - 1) < 0)
findState.startpos = 0;
I may be misunderstanding the intention of the code, but why does it subtract one here? AFAICS, this will create an off-by-one error when searching backwards.
Am loading a listbox in TKinter. The string is a collection of fields from a matrix. 4 fields, 1 date, 1 float, and 2 text.
However, because of proportional fonts, I cannot get the text in each line to line up into columns.
Here is my current code
from tkinter import *
from tkinter import ttk
from datetime import *
import locale
# for currency display, set the locale
locale.setlocale( locale.LC_ALL, '' )
class main_gui(Frame):
def __init__(self): #Intialize key variables and call the main screen.
self.Ledgerdata = [ ]
print ("main_gui __init__")
self.load_data()
self.main_screen()
def load_data(self):
# stub for testing - to be rewritten to read external file and load into Ledgerdata.
entry = []
entry.append("4/17/2016, 24, 1, Doctor")
entry.append("4/18/2016, 32, 1, Mechanic whose name is bill")
entry.append("4/19/2016, 45, 1, Grocery")
entry.append("4/11/2016, 19, 1, Puppet")
entry.append("4/17/2016, 119.50, 1, Johns Computer House")
entry.append("4/11/2016, 1250, 1, Sidney Barthalmew")
for entry_index in range(len(entry)):
entry[entry_index] = entry[entry_index].split(",")
date_conversion = entry[entry_index][0].split("/") # Convert date from text string
entry[entry_index][0] = date(int(date_conversion[2]), # to datetime variable
int(date_conversion[0]),
int(date_conversion[1]))
self.Ledgerdata.append((entry[entry_index][0], # Add transaction to Ledgerdata
float(entry[entry_index][1]),
int(entry[entry_index][2]),
entry[entry_index][3]))
#====== Data from file is read and loaded into Ledgerdata
#main_screen - main display screen for Ledgerdata
# Will show list of transactions, total for each category,
# with buttons to Add, Edit, Delete, Create Summary and Exit
def main_screen(self):
root = Tk() # reference to the GUI toolkit
main_window = ttk.Frame(root)
main_window.grid(row=0,column=0) # overall Frame
display_frame = ttk.Frame(main_window) # list display frame
display_frame.grid(column=0, row = 0)
option_frame = ttk.Frame(main_window) # selection frame - to be written.
option_frame.grid(column=0, row=15, columnspan=8)
summary_frame = ttk.Frame(main_window)
summary_frame.grid(column = 10, row = 0)
summary_frame.columnconfigure(0, minsize=50)
summary_frame.columnconfigure(1, minsize=250)
#Start display frame
list_header = Label(display_frame, width = 100, # Header line for List
font = 12,anchor = W, # NEEDS CLEANUP
text = " Date Amount Description Code")
list_header.grid(row=1)
list_of_transactions = Listbox(display_frame,width =100, height = 20, font = 12) #Generate listbox widget
list_of_transactions.grid(row=2, column = 0)
# Loop for number of transactions in Ledgerdata. Loop adds formatted transaction info to list_of_transactions
# liststring object for display
for x in range(len(self.Ledgerdata)):
output_string = '{0:10} {1:>8} {2:<50} {3:<40}'.format(
str(self.Ledgerdata[x][0].strftime("%m/%d/%y"))
,locale.currency(self.Ledgerdata[x][1], grouping=True)
,(self.Ledgerdata[x][3])
,(self.Ledgerdata[x][2]))
list_of_transactions.insert(x,output_string)
list_of_transactions.grid(row=x, column = 0)
#main_window.pack()
mainloop()
main_gui()
Anyone know how to get elements in strings to text to maintain the same width???
Thanks as always,
Darrell
EDITTED - Per request, added entire code segment that can be run. I had to take this out of my main program, eliminate several parts that are not relevant to the problem at hand, and make some changes that do not affect the problem at hand. So this is just a standalone testbed.