Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Tkinter:用鼠标拖动没有边框的窗口,例如overridedirect(1)_Python_Windows_User Interface_Window_Tkinter - Fatal编程技术网

Python Tkinter:用鼠标拖动没有边框的窗口,例如overridedirect(1)

Python Tkinter:用鼠标拖动没有边框的窗口,例如overridedirect(1),python,windows,user-interface,window,tkinter,Python,Windows,User Interface,Window,Tkinter,关于如何创建允许用户用鼠标拖动无边框窗口(例如使用overridedirect(1)创建的窗口)的事件绑定的任何建议 用例:我们希望创建一个浮动工具栏/调色板窗口(无边框),用户可以在桌面上拖动它 以下是我的想法(伪代码): window.bind(“”,onMouseDown)捕获鼠标的初始位置 window.bind(“”,onMouseMove)在鼠标开始移动时跟踪鼠标的位置 计算鼠标移动了多少并计算newX,newY位置 使用window.geometry('++%d++%d%%(new

关于如何创建允许用户用鼠标拖动无边框窗口(例如使用
overridedirect(1)
创建的窗口)的事件绑定的任何建议

用例:我们希望创建一个浮动工具栏/调色板窗口(无边框),用户可以在桌面上拖动它

以下是我的想法(伪代码):

  • window.bind(“”,onMouseDown)
    捕获鼠标的初始位置

  • window.bind(“”,onMouseMove)
    在鼠标开始移动时跟踪鼠标的位置

  • 计算鼠标移动了多少并计算
    newX
    newY
    位置

  • 使用
    window.geometry('++%d++%d%%(newX,newY))
    移动窗口


  • Tkinter是否公开了足够的功能以允许我实现手头的任务?还是有更简单/更高层次的方法来实现我想要做的事情?

    是的,Tkinter公开了足够的功能来实现这一点,没有更简单/更高层次的方法来实现你想要做的事情。你的想法很正确

    这里有一个例子,但这不是唯一的方法:

    import tkinter as tk
    
    class App(tk.Tk):
        def __init__(self):
            tk.Tk.__init__(self)
            self.floater = FloatingWindow(self)
    
    class FloatingWindow(tk.Toplevel):
        def __init__(self, *args, **kwargs):
            tk.Toplevel.__init__(self, *args, **kwargs)
            self.overrideredirect(True)
    
            self.label = tk.Label(self, text="Click on the grip to move")
            self.grip = tk.Label(self, bitmap="gray25")
            self.grip.pack(side="left", fill="y")
            self.label.pack(side="right", fill="both", expand=True)
    
            self.grip.bind("<ButtonPress-1>", self.start_move)
            self.grip.bind("<ButtonRelease-1>", self.stop_move)
            self.grip.bind("<B1-Motion>", self.do_move)
    
        def start_move(self, event):
            self.x = event.x
            self.y = event.y
    
        def stop_move(self, event):
            self.x = None
            self.y = None
    
        def do_move(self, event):
            deltax = event.x - self.x
            deltay = event.y - self.y
            x = self.winfo_x() + deltax
            y = self.winfo_y() + deltay
            self.geometry(f"+{x}+{y}")
    
    app=App()
    app.mainloop()
    
    将tkinter作为tk导入
    类应用程序(tk.tk):
    定义初始化(自):
    tk.tk.\uuuuu初始化(self)
    self.floater=浮动窗口(self)
    类浮动窗口(tk.Toplevel):
    定义初始化(self,*args,**kwargs):
    tk.Toplevel.\uuuuu初始化(self,*args,**kwargs)
    self.overrideredirect(True)
    self.label=tk.label(self,text=“单击夹点移动”)
    self.grip=tk.Label(self,bitmap=“gray25”)
    自握力包装(side=“left”,fill=“y”)
    self.label.pack(side=“right”,fill=“both”,expand=True)
    self.grip.bind(“,self.start\u move)
    self.grip.bind(“,self.stop\u move)
    self.grip.bind(“,self.do\u move)
    def start_移动(自身、事件):
    self.x=event.x
    self.y=event.y
    def停止_移动(自身、事件):
    self.x=无
    self.y=None
    def do_移动(自身、事件):
    deltax=event.x-self.x
    deltay=event.y-self.y
    x=self.winfo_x()+deltax
    y=self.winfo_y()+deltay
    自几何(f“+{x}+{y}”)
    app=app()
    app.mainloop()
    
    试试这个,它肯定会奏效

  • 创建事件函数以移动窗口:

    def移动窗口(事件): 几何体('+{0}+{1}'。格式(event.x_root,event.y_root))

  • 绑定窗口:

    root.bind(“”,移动窗口)


  • 现在您可以触摸窗口并拖动

    此代码与Bryan的解决方案相同,但它不使用overridedirect

    它是用python 3.7、Debian GNU/Linux 10(buster)、Gnome 3.30测试的

    import tkinter as tk
    
    
    class App(tk.Tk):
        def __init__(self):
            tk.Tk.__init__(self)
            self.floater = FloatingWindow(self)
    
    
    class FloatingWindow(tk.Toplevel):
        def __init__(self, *args, **kwargs):
            tk.Toplevel.__init__(self, *args, **kwargs)
    
            #self.overrideredirect(True)
            self.resizable(0, 0)  # Window not resizable
            self.wm_attributes('-type', 'splash')  # Hide title bar (Linux)
    
            self.label = tk.Label(self, text="Click on the grip to move")
            self.grip = tk.Label(self, bitmap="gray25")
            self.grip.pack(side="left", fill="y")
            self.label.pack(side="right", fill="both", expand=True)
    
            self.grip.bind("<ButtonPress-1>", self.StartMove)
            self.grip.bind("<ButtonRelease-1>", self.StopMove)
            self.grip.bind("<B1-Motion>", self.OnMotion)
    
        def StartMove(self, event):
            self.x = event.x
            self.y = event.y
    
        def StopMove(self, event):
            self.x = None
            self.y = None
    
        def OnMotion(self, event):
            deltax = event.x - self.x
            deltay = event.y - self.y
            x = self.winfo_x() + deltax
            y = self.winfo_y() + deltay
            self.geometry("+%s+%s" % (x, y))
    
    
    app = App()
    app.mainloop()
    
    将tkinter作为tk导入
    类应用程序(tk.tk):
    定义初始化(自):
    tk.tk.\uuuuu初始化(self)
    self.floater=浮动窗口(self)
    类浮动窗口(tk.Toplevel):
    定义初始化(self,*args,**kwargs):
    tk.Toplevel.\uuuuu初始化(self,*args,**kwargs)
    #self.overrideredirect(True)
    自我调整大小(0,0)#窗口不可调整大小
    self.wm_属性('-type',splash')#隐藏标题栏(Linux)
    self.label=tk.label(self,text=“单击夹点移动”)
    self.grip=tk.Label(self,bitmap=“gray25”)
    自握力包装(side=“left”,fill=“y”)
    self.label.pack(side=“right”,fill=“both”,expand=True)
    self.grip.bind(“,self.StartMove)
    self.grip.bind(“,self.StopMove)
    self.grip.bind(“,self.OnMotion)
    def StartMove(自身、事件):
    self.x=event.x
    self.y=event.y
    def停止移动(自身、事件):
    self.x=无
    self.y=None
    def OnMotion(自身、事件):
    deltax=event.x-self.x
    deltay=event.y-self.y
    x=self.winfo_x()+deltax
    y=self.winfo_y()+deltay
    自几何体(“++%s++%s”%(x,y))
    app=app()
    app.mainloop()
    
    Loïc Faure Lacroix的想法很有用,下面是我自己关于Python3.7.3的简单代码片段,希望能有所帮助:

    from tkinter import *
    
    
    def move_window(event):
        root.geometry(f'+{event.x_root}+{event.y_root}')
    
    
    root = Tk()
    root.bind("<B1-Motion>", move_window)
    root.mainloop()
    
    从tkinter导入*
    def move_窗口(事件):
    几何体(f'+{event.x_root}+{event.y_root}')
    root=Tk()
    root.bind(“,移动窗口)
    root.mainloop()
    
    但是鼠标的位置总是在窗口的左上角。我怎样才能保持不变?期待更好的答案


    感谢布莱恩·奥克利,因为一开始我无法在我的电脑上运行你的代码,我没有注意到它。刚才修改后运行的很好,不会出现上述情况(鼠标总是在左上角),最近更新的代码如下:

    def widget_drag_free_bind(widget):
        """Bind any widget or Tk master object with free drag"""
        if isinstance(widget, Tk):
            master = widget  # root window
        else:
            master = widget.master
    
        x, y = 0, 0
        def mouse_motion(event):
            global x, y
            # Positive offset represent the mouse is moving to the lower right corner, negative moving to the upper left corner
            offset_x, offset_y = event.x - x, event.y - y  
            new_x = master.winfo_x() + offset_x
            new_y = master.winfo_y() + offset_y
            new_geometry = f"+{new_x}+{new_y}"
            master.geometry(new_geometry)
    
        def mouse_press(event):
            global x, y
            count = time.time()
            x, y = event.x, event.y
    
        widget.bind("<B1-Motion>", mouse_motion)  # Hold the left mouse button and drag events
        widget.bind("<Button-1>", mouse_press)  # The left mouse button press event, long calculate by only once
    
    def widget\u drag\u free\u bind(widget):
    “”“使用自由拖动绑定任何小部件或Tk主对象”“”
    如果isinstance(小部件,Tk):
    master=widget#根窗口
    其他:
    master=widget.master
    x、 y=0,0
    定义鼠标运动(事件):
    全局x,y
    #正偏移表示鼠标移动到右下角,负偏移表示鼠标移动到左上角
    偏移量x,偏移量y=event.x-x,event.y-y
    new_x=master.winfo_x()+offset_x
    new_y=master.winfo_y()+offset_y
    new_geometry=f“+{new_x}+{new_y}”
    几何硕士(新几何)
    def鼠标按下(事件):
    全局x,y
    计数=时间。时间()
    x、 y=事件.x,事件.y
    widget.bind(“,鼠标移动)#按住鼠标左键并拖动事件
    widget.bind(“,鼠标按下)#鼠标左键按下事件,长按只计算一次
    
    以下是我的解决方案:

    from tkinter import *
    from webbrowser import *
    
    
    lastClickX = 0
    lastClickY = 0
    
    
    def SaveLastClickPos(event):
        global lastClickX, lastClickY
        lastClickX = event.x
        lastClickY = event.y
    
    
    def Dragging(event):
        x, y = event.x - lastClickX + window.winfo_x(), event.y - lastClickY + window.winfo_y()
        window.geometry("+%s+%s" % (x , y))
    
    
    window = Tk()
    window.overrideredirect(True)
    window.attributes('-topmost', True)
    window.geometry("400x400+500+300")
    window.bind('<Button-1>', SaveLastClickPos)
    window.bind('<B1-Motion>', Dragging)
    window.mainloop()
    
    从tkinter导入*
    从webbrowser导入*
    lastClickX=0
    lastClickY=0
    def SaveLastClickPos(事件):
    全局lastClickX,lastClickY
    lastClickX=event.x
    lastClickY=event.y
    def拖动(事件):
    x、 y=event.x-lastClickX+window.winfo_x(),event.y-lastClickY+wi