6
\$\begingroup\$

I have a QTreeview that is filled with data from data_for_tree dictionary. Suppose that dictionary represents the most common purchases a person makes. I call it "source list".

Data, shown in that list differs from data that is shown in the "receiver list". Suppose a person inserted it via special form. The goal is - by clicking twice add data from source list to receiver list in proper format and in a proper way.

The goal is reached, but it seems to me, by the very complicated way. First I get the selected items, then compare them to data_for_tree dictionary and get the rest of data (that is not shown), then make new item that is a tuple of QStandardItems, then add it to "receiver list", then update a dictionary for the "receiver list".

I am sure that there is a better way for performing it. But due to my beginner's level I couldn't apply it. I'm going to add drag and drop option in the nearest future, and I think may be there is a shared (common) way for adding items by double clicking and drag'n'drop methods from one list to another.

I ask for improvements, optimization and comments.

#!/usr/bin/env python -tt
# -*- coding: utf-8 -*-
#from PySide.QtGui import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

import sys
reload(sys)
sys.setdefaultencoding('utf8')

data_for_tree = {"tomato":{"color":"red","ammount":"10", "note":"a note for tomato","price":"0.8"},"banana":{"color":"yellow","ammount":"1", "note":"b note for banana", "price":".6"}, "some fruit":{"color":"unknown","ammount":"100", "note":"some text","price":"2.1"}}
data_for_receiver = {"1":{"name":"milk","price":"3.2","note":"I love milk"}, "2":{"name":"coca-cola","price":".8","note":"coke forever"}}

class ProxyModel(QSortFilterProxyModel):

    def __init__(self, parent=None):
        super(ProxyModel, self).__init__(parent)

    def lessThan(self, left, right):
        leftData = self.sourceModel().data(left)
        rightData = self.sourceModel().data(right)
        try:
           return float(leftData) < float(rightData)
        except ValueError:
            return leftData < rightData

class MainFrame(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        self.MyTreeView = QTreeView()
        self.MyTreeViewModel = QStandardItemModel()
        self.MyTreeView.setModel(self.MyTreeViewModel)
        self.most_used_cat_header = ['Name', "ammount", "color"]
        self.MyTreeViewModel.setHorizontalHeaderLabels(self.most_used_cat_header)
        self.MyTreeView.setSortingEnabled(True)

        self.MyTreeView_Fill()

        self.receiver_tree = QTreeView()
        self.receiver_model = QStandardItemModel()
        self.receiver_tree.setModel(self.receiver_model)
        self.receiver_tree_header = ['#','Name', "price"]
        self.receiver_model.setHorizontalHeaderLabels(self.receiver_tree_header)


        self.MyTreeView.doubleClicked.connect(self.addToReceiver)

        self.receiver_fill()

        MainWindow = QHBoxLayout(self)    
        MainWindow.addWidget(self.MyTreeView)
        MainWindow.addWidget(self.receiver_tree)
        self.setLayout(MainWindow)

    def addToReceiver(self):
        indexes = self.MyTreeView.selectedIndexes()
        index_list =[i.data() for i in self.MyTreeView.selectedIndexes()]
        last_id = max(int(i) for i in data_for_receiver)
        for k in data_for_tree:
            v = data_for_tree[k]
            if [k,v["ammount"],v["color"]] == index_list:
                i =QStandardItem(str(last_id+1))
                name = QStandardItem(k)
                price = QStandardItem(format(float(v["price"]), ".2f"))
                tooltip = v["note"]
                name.setToolTip(tooltip)
                item = ( i, name, price)
                self.receiver_model.appendRow(item)
                upd  = {"name":k,"price":v["price"],"note":v["note"]}
                data_for_receiver[str(last_id+1)] = upd

    def MyTreeView_Fill(self):
        for k in data_for_tree:
            name = QStandardItem(k)
            ammount = QStandardItem(data_for_tree[k]["ammount"])
            note = QStandardItem(data_for_tree[k]["color"])
            name.setEditable(False)
            tooltip = "price "+format(float(data_for_tree[k]["price"]), ".2f")+"<br>"
            tooltip += data_for_tree[k]["note"]
            item = (name, ammount, note)
            name.setToolTip(tooltip)

            self.MyTreeViewModel.appendRow(item)
        self.MyTreeView.sortByColumn(1, Qt.DescendingOrder)
        proxyModel = ProxyModel(self)
        proxyModel.setSourceModel(self.MyTreeViewModel)
        self.MyTreeView.setModel(proxyModel)

        c = 0
        while c < len(self.most_used_cat_header):
            self.MyTreeView.resizeColumnToContents(c)
            c=c+1

    def receiver_fill(self):
        for k in data_for_receiver:
            v = data_for_receiver[k]
            i = QStandardItem(k)
            name = QStandardItem(v["name"])
            price = QStandardItem(format(float(v["price"]), ".2f"))
            tooltip = v["note"]
            name.setToolTip(tooltip)

            item = (i,name, price)
            self.receiver_model.appendRow(item)
        c = 0
        while c < len(self.receiver_tree_header):
            self.receiver_tree.resizeColumnToContents(c)
            c=c+1

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = MainFrame()
    main.show()
    main.move(app.desktop().screen().rect().center() -     main.rect().center())
    sys.exit(app.exec_())
\$\endgroup\$
5
\$\begingroup\$

while loops are appropriate for iterating an unknown amount of times, such as while i == True: i = int(input("> ")) / 2 == 0. This will iterate until the user inputs a value divisible by 2.

for loops are appropriate for iterating over a known range, such as for i in range(0, 10): print(i), which will print the numbers 0..9 inclusive.

Here, you are using a while loop where a for loop is more appropriate:

c = 0
while c < len(self.most_used_cat_header):
    self.MyTreeView.resizeColumnToContents(c)
    c=c+1

This should be:

for c in range(0, len(self.most_used_cat_header)):
    self.MyTreeView.resizeColumnToContents(c)

c in the above example is not a particularly informative name. What does it represent, an index in an array? You also use other uninformative names, including k, v, i, and more. Name length is no longer limited by languages, nor do they affect runtime anymore.


Here, you assign a variable two statements in a row:

tooltip = "price "+format(float(data_for_tree[k]["price"]), ".2f")+"<br>"
tooltip += data_for_tree[k]["note"]

Why not join those into a single statement? Because Python's strings are immutable, you are first create a string out of the multiple strings added to each other, then create another string. The performance cost here is nothing to worry about, but this is an issue you should consider when heavily mutating strings.


Your operator spacing looks nice for the most part, but occasionally you will do '= ' (missing first space) or ' = ' (two spaces at beginning) rather than =. Consistent code is easier to read, although this is not bad at all.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.