Tkinter - 在屏幕一角显示遗忘标签的错误?

时间:2017-06-13 02:28:07

标签: python-3.x tkinter

屏幕截图:http://puu.sh/wiuP7/957bca09ea.png

我的代码已附上并大致执行以下操作:

从SQL服务器获取数据

对于每种产品,它列出了所有印刷产品和所有扫描产品。可能有多个打印件(参见底部的P039)。它使用标签来做到这一点。

它使用after()运行每5秒,当它运行时,它使用grid_forget()删除所有“旧”标签..它运行for循环并且更新的标签在那里,5秒后没有眨眼或任何明显的中断。

问题:在一段不确定的时间后,它将不再正确循环。它不会显示任何标签,并且会在窗口的左上角看起来像一堆标签。但是在屏幕截图中,角落中的堆实际上是因为我关闭了脚本的实例,所以到目前为止,打开的实例(所有标签都正确)都是好的。角落中的错误来自先前关闭的实例。尽管如此,如果我没有再次打开它,你将看不到任何产品和数字列表。

无论如何,这总会发生。我了解到增加after()延迟也会增加它发生的时间。例如,当延迟为2000毫秒时,它发生在大约20-30分钟,但是当延迟为10000毫秒时,需要数小时(不确定多长时间,至少5分钟)。

使用不同的函数手动运行函数顶部的for循环,并且按钮无法修复它。

我在python 3.6.1上使用tkinter。我在Windows 10和Windows Server 2008 r2上通过远程桌面看到了它

感兴趣的代码如下,这完成了更新等所有工作。我的整个代码很长,但这里也是我的包含:

编辑:如果程序最小化,似乎不会发生。

import time
import threading
import logging
import datetime
import tkinter as tk
from tkinter import *
import tkinter.scrolledtext as ScrolledText
from tkinter.ttk import Separator, Style
from collections import Counter
import pypyodbc

这是更新功能:

def build_productionrpt(self, LotDate, Shift):
    for label in self.grid_slaves():
        if int(label.grid_info()["column"]) >= 0 and int(label.grid_info()["row"]) >= 3:
            label.grid_forget()
    self.products = []
    self.r = 3
    self.c = 0

    # Get all printed labels for current date and shift
    labels = ProductionReport.LabelsByShift(LotDate,Shift,option="Labels")
    # Only look at the DatePrinted and the ProductID
    product_batch_sets = [(record[0], record[1]) for record in labels]
    # Sort so that we only get unique values, otherwise there would be a duplicate for every unit.
    product_batch_unique_sets = list(set(product_batch_sets))

    # Get all units for each batch and sort by PrintedDate, UnitNumber, and RFIDSerial. Currently we are not using RFIDSerial for anything in this report
    batch_unit_sets = [(record[0], record[6], record[5]) for record in labels]
    # Sort so that we only get unique values, otherwise there would be a duplicate for every unit.
    batch_unit_unique_sets = list(set(batch_unit_sets))

    # Get all scanned labels for current date and shift, sort by PrintedDate, UnitNumber, and RFIDSerial. Currently we are not using RFIDSerial for anything in this report
    units_scanned_sets = [(record[0], record[6], record[5]) for record in ProductionReport.LabelsByShift(LotDate,Shift,option="Scanned")]
    # Remove all duplicate scans 
    units_scanned_unique_sets = list(set(units_scanned_sets))

    # Begin by going through each row
    for record in product_batch_unique_sets:
        # Get each unique product from the list, if it's already in self.products then it's been Labeled and we can move on
        if record[1] not in self.products:
            # Add to self.products so we don't label it twice
            self.products.append(record[1])
            # Label it on the GUI, using row 3 as the first row.
            # First, make sure the labels haven't gotten too far. If it has, reset the row count and change the column
            if self.r > 35:
                self.c = 1
                self.r = 2
            elif self.r > 35 and self.c == 1:
                self.c = 2
                self.r = 2
            Label(self, text=record[1], font=("Helvetica", 16, "bold")).grid(row=self.r, column=self.c, sticky="nw", rowspan=3)
            # Add 3 rows to r, to make room for the Product label.
            self.r+=3
            # Set the current product to what we just labeled, so we know what to use as a reference when getting batches.
            current_product = record[1]
            # Get all batches for this product and put them in a list
            all_batches = [i for i,v in product_batch_unique_sets if v == current_product]
            # Now take each batch from the list we just made..
            for batch in all_batches:
                # Label it
                # Label(self, text=str(batch), font=("Helvetica", 10)).grid(row=self.r, column=0, sticky="nw")
                # Add 2 rows to make room for the batch and for the unit numbers
                # Get all unitnumbers printed for this specific batch
                all_unitnumbers = [v for i,v,u in batch_unit_unique_sets if i == batch]
                # Sort them so it's readable
                all_unitnumbers.sort()
                # Get all units that were scanned from this batch
                all_scannedunits = [v for i,v,u in units_scanned_unique_sets if i == batch]
                # Sort them so it's readable
                all_scannedunits.sort()
                # Label the scanned units, they are green
                Label(self, text=str(all_scannedunits), font=("Helvetica", 8), wraplength=500, justify="left", fg="green").grid(row=self.r, column=self.c, sticky="nw", padx=20)
                # Add 2 rows to make room for the unscanned units
                self.r+=2
                # This takes all printed units, and subtracts all scanned units from that. What's left is the units that were printed but not scanned
                a = Counter(all_unitnumbers)
                b = Counter(all_scannedunits)
                c = a - b
                # Label all units printed but not scanned
                Label(self, text=str(list(c.elements())), font=("Helvetica", 8), wraplength=500, justify="left", fg="red").grid(row=self.r, column=self.c, sticky="nw", padx=20)
                # Add two rows to make room for the next Product
                self.r+=2

                # all_noscans = [v for i,v,u in units_noscan_unique_sets if i == batch]
                # Label(self, text=str(all_noscans), font=("Helvetica", 8)).grid(row=self.r, column=0, sticky="nw", padx=20)
                # self.r+=3
    if should_continue_prod_report:
        self.after(5000, lambda:self.build_productionrpt(self.lotdate_e.get(), self.shift_e.get()))

1 个答案:

答案 0 :(得分:0)

我能够通过以下方式解决此问题: 将所有标签存储在字典中,其密钥类似于ProductVariable +“_ label”,值将为标签

将所有textvariables存储在同一个字典中。我不得不将标签(root,text = ..)更改为label(root,textvariable = ..)

在每个for循环中,检查并查看标签是否存在。如果是,请使用set()更新它。

基本上,每隔5秒钟创建一个标签并忘记旧标签作为实时更新数据的方法是不好的做法。