Python tkinter画布闪烁 [英] Python tkinter canvas flickering

查看:52
本文介绍了Python tkinter画布闪烁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先我要声明我知道本网站上有其他类似名称的帖子.我经历过他们,但据我所知,他们没有解决我的问题.我实际上会说我的问题比大多数示例要简单得多.

Firstly I should state that I am aware of other posts on this site with similar names. I have been through them but they do not, so far as I can tell, address my problem. I would actually say my problem is far more simple than most of those examples.

简单地说,我想创建一个透明的矩形,我可以用它来显示拖动选择区域.当我发现 tkinter 不做透明度时,我决定简单地绘制四条线来创建矩形的外观,而不在这些线之间绘制任何东西.不理想,但对于我的小项目来说已经足够了(尽管如果有人知道一个可以处理透明度和颜色渐变以及无需大惊小怪的东西的库,我完全听得懂).

Simply put, I wanted to create a transparent rectangle that I could use to show a drag select area. When I found out that tkinter doesn't do transparency, I decided on the idea of simply drawing four lines to create the appearance of a rectangle without drawing anything between those lines. Not ideal, but for my small project it was enough (although if anyone knows a library that does transparency and colour gradients and things without much fussing around, I'm all ears).

所以我创建了我的画布.在鼠标按下时,我保存了坐标并在该坐标处创建了四条线(实际上是一个像素矩形),在鼠标移动时,我使用了 canvas.coords 方法来移动这些线.在鼠标抬起时,我使用 canvas.delete 删除了线条.

So I created my canvas. On mouse down I saved the coordinates and also created four lines at that coordinate (effectively a one pixel rectangle), and on mouse move I used the canvas.coords method to move the lines. On mouse up I removed the lines, using canvas.delete.

代码似乎工作正常,但问题在于(我认为是)画布的更新.如果我真的很慢地点击并拖动,矩形就会出现我想要的样子.如果我移动得更快(我应该澄清一下,我认为这个拖动速度在正常使用范围内),底部和右侧的线条就会消失,直到鼠标变慢或停止.如果我像疯了一样挥动鼠标,我可能会理解,但是发生这种情况的速度确实没有那么快.因此,线条非常明显地消失或闪烁,因为偶尔更新速度足以跟踪移动的鼠标.

The code seems to work fine, but it's (what I assume is) the updating of the canvas that's the problem. If I click and drag really slowly, the rectangle will appear as I want it to. If I move faster (and I should clarify that I consider this drag speed to be well within normal usage), the bottom and right lines just disappear until the mouse either slows down or stops. Had I been whizzing the mouse around like crazy I might have understood, but the speed at which this happens is really not that fast. So the lines very visibly either disappear, or flicker as occasionally the update is fast enough to keep track of the moving mouse.

基本上它看起来很糟糕,但是有一些值得注意的地方.因此,如果我向下和向右拖动鼠标(使框更大),就会发生这种效果.当我将它拖回开始时,要制作一个较小的框,无论我尝试多快都不会发生.我确定这是画布小部件的一些怪癖,但我想知道如何修复它,或者人们是否刚刚使用其他库而不是 tkinter(如果是这样,它们是什么?)

Basically it looks pretty bad, however there is something of note. So if I drag my mouse down and to the right (to make the box larger), this effect will happen. When I drag it back to the start, to make a smaller box, it does not occur no matter how fast I try to do it. I'm sure this is some quirk of the canvas widget, but I'd like to know either how to fix it or if people have just gone on to other libraries instead of tkinter (if so, what are they?)

代码就和这种事情一样简单:

The code is about as simple as it comes for this kind of thing:

def OnLeftMouseDown(event):
    global InitialX, InitialY, Line1ID, Line2ID, Line3ID, Line4ID
    InitialX = event.x
    InitialY = event.y
    Line1ID = canvas.create_line(event.x, event.y, event.x, event.y, fill='green')
    Line2ID = canvas.create_line(event.x, event.y, event.x, event.y, fill='green')
    Line3ID = canvas.create_line(event.x, event.y, event.x, event.y, fill='green')
    Line4ID = canvas.create_line(event.x, event.y, event.x, event.y, fill='green')

def OnLeftMouseUp(event):
    canvas.delete(Line1ID)
    canvas.delete(Line2ID)
    canvas.delete(Line3ID)
    canvas.delete(Line4ID)

def OnLeftMouseMove(event):
    canvas.coords(Line1ID, InitialX, InitialY, InitialX, event.y)
    canvas.coords(Line2ID, InitialX, InitialY, event.x, InitialY)
    canvas.coords(Line3ID, event.x, InitialY, event.x, event.y)
    canvas.coords(Line4ID, InitialX, event.y, event.x, event.y)


root = tk.Tk()
root.geometry("1000x600")

global InitialX, InitialY
global Line1ID, Line2ID, Line3ID, Line4ID

canvas = tk.Canvas(root, width=800, height=600, bg='white')
canvas.pack()

canvas.bind("<ButtonPress-1>", OnLeftMouseDown)
canvas.bind("<B1-Motion>", OnLeftMouseMove)
canvas.bind("<ButtonRelease-1>", OnLeftMouseUp)

root.mainloop()

我在画布上拖动其他项目时也遇到了这个问题.我想要一系列视觉节点",它们只是包含信息的帧.以正常速度拖动它们会切断框架的最右侧和最底部部分.

I've had this problem while dragging other items on a canvas too. I wanted a series of visual 'nodes' that were just frames containing information. Dragging them at even a normal speed cut off the right most and bottom most parts of the frame.

我的操作系统是 Windows 7.我尝试了下面由用户 scicroccorics 建议的代码,还尝试将画布方法update_idletasks"添加到我自己的代码中.没变.我的程序有闪烁,而 Sciroccorics 的代码也有同样的闪烁.此外,我使用 Microsoft Expression Encoder 4 来捕获桌面以显示正在发生的事情.使用屏幕截图和该程序,我看不到任何可见的闪烁/消失的线条(即使我将录音机设置为以 60fps 进行录制).虽然我可以用我的手机记录我所看到的,所以我们可以在这里看到:闪烁的 Vimeo 视频

My OS is Windows 7. I have tried the code suggested below by user sciroccorics and have also tried adding to my own code the canvas method 'update_idletasks'. No change. My program has the flicker and sciroccorics' code has the same flicker. Furthermore I've used Microsoft Expression Encoder 4 to capture the desktop to show what's going on. With screen caps and that program, I get no visible flicking / disappearing lines (even when I set the recorder to record at 60fps). Although I was able to use my phone to record what I was seeing so we can see that here: Vimeo vid of flickering

推荐答案

这是您示例的最小版本,使用一个矩形而不是四行(我在画布上添加了一个蓝色圆圈,以显示矩形是透明的).它在我的(相当旧的)笔记本电脑上没有显示任何闪烁或消失的边缘.它在您的设备上如何?

Here is the minimal version of your example, using one rectangle instead of four lines (I've added a blue circle on the canvas, to show that the rectangle is transparent). It does not show any flickering or vanishing edges on my (rather old) laptop. How is it on your device?

正如@stovfl 所指出的,tkinter 显示刷新在 Windows 10 上确实比在 Windows 7 上的效率低得多(因为它一直在 Linux/X11 上效率已经低得多).我在鼠标移动回调上添加了一个 update_idletasks(),因为它有时会改善刷新错误.您可以将其注释掉,并测试它是否有任何区别.

As noted by @stovfl, tkinter display refreshing is indeed much less efficient on Windows 10 as it used to be on Windows 7 (which was already much less efficient as it has always been on Linux/X11). I added an update_idletasks() on the mouse move callback, as it sometimes improves refreshing errors. You may comment it out, and test if it offers any difference.

import tkinter as tk

def OnLeftMouseDown(event):
    global InitialX, InitialY, RectID
    InitialX, InitialY = event.x, event.y
    RectID = canvas.create_rectangle(InitialX, InitialY, InitialX, InitialY)

def OnLeftMouseUp(event):
    canvas.delete(RectID)

def OnLeftMouseMove(event):
    canvas.update_idletasks()
    canvas.coords(RectID, InitialX, InitialY, event.x, event.y)

root = tk.Tk()

canvas = tk.Canvas(root, width=800, height=600, bg='white')
canvas.pack()
canvas.create_oval(200, 200, 400, 400, fill='blue')

canvas.bind("<ButtonPress-1>", OnLeftMouseDown)
canvas.bind("<B1-Motion>", OnLeftMouseMove)
canvas.bind("<ButtonRelease-1>", OnLeftMouseUp)

root.mainloop()

这篇关于Python tkinter画布闪烁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆