仅当光标悬停在标签上时,如何将光标更改为手?

时间:2017-07-19 08:03:48

标签: python tkinter

from tkinter import *
root = Tk()
def changeCursor(event, pointerName):
    root.cursor(pointerName)
link = Label(root, text="Link")
link.bind("<Motion>", lambda event : changeCursor(event, "hand"))
link.pack()
root.mainloop()

当我的光标悬停在光标上时,我希望我的光标变成“手”。当光标离开标签占据的区域时,我还想将光标改回箭头。但是我收到以下错误:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Arnob\AppData\Local\Programs\Python\Python36-
32\lib\idlelib\run.py", line 137, in main
    seq, request = rpc.request_queue.get(block=True, timeout=0.05)
  File "C:\Users\Arnob\AppData\Local\Programs\Python\Python36-
32\lib\queue.py", line 172, in get
   raise Empty
queue.Empty

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Arnob\AppData\Local\Programs\Python\Python36-
32\lib\tkinter\__init__.py", line 1699, in __call__
    return self.func(*args)
  File "<pyshell#7>", line 1, in <lambda>
  File "<pyshell#4>", line 2, in changePointer
  File "C:\Users\Arnob\AppData\Local\Programs\Python\Python36-
32\lib\tkinter\__init__.py", line 2095, in __getattr__
    return getattr(self.tk, attr)
AttributeError: '_tkinter.tkapp' object has no attribute 'cursor'

当光标位于Label所占区域时,如何将光标更改为手形,然后当光标离开Label所占区域时将其更改回箭头?

3 个答案:

答案 0 :(得分:1)

如果您希望光标始终是手,只需将标签配置为具有该光标:

using System;
using System.Reactive.Linq;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using System.Collections.ObjectModel;

namespace Sandbox
{

    public class SandboxNotifiableViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged<TProperty>(Expression<Func<TProperty>> projection)
        {
            var memberExpression = (MemberExpression) projection.Body;
            this.RaisePropertyChanged(memberExpression.Member.Name);
        }

        public void RaisePropertyChanged([CallerMemberName] string propertyName = "")
            => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public class TestViewModel : SandboxNotifiableViewModel
    {
        private class SandBoxCommand : ICommand
        {
            private readonly Action cbk;
            public event EventHandler CanExecuteChanged;

            private void WarningRemover()
                => this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);

            public SandBoxCommand(Action cbk)
            {
                this.cbk = cbk;
            }

            public bool CanExecute(object parameter)
                => true;
            public void Execute(object parameter)
                => this.cbk?.Invoke();
        }

        public TestViewModel()
        {
            this.AddLongTask = new SandBoxCommand(this.AddLongTaskAction);
            this.LongTasks = new ObservableCollection<LongTaskViewModel>();
        }

        public ObservableCollection<LongTaskViewModel> LongTasks { get; }

        private void AddLongTaskAction()
            => this.LongTasks.Add(new LongTaskViewModel());

        public ICommand AddLongTask { get; } 
    }

    public class LongTaskViewModel : SandboxNotifiableViewModel
    {
        private bool isFinished;
        private int progress;


        public LongTaskViewModel()
        {
            this.Progress = 0;
            this.IsFinished = false;
            // Refresh progress every 10ms 100 times 
            Observable.Interval(TimeSpan.FromMilliseconds(10))
                .Select(x => x + 1) // 1 to 100
                .Take(100)
                // Here we make sure observable callback is called on dispatcher thread
                .ObserveOnDispatcher()
                .SubscribeOnDispatcher()
                .Subscribe(this.OnProgressReported, this.OnLongTaskFinished);
        }

        public bool IsFinished
        {
            get => this.isFinished;
            set
            {
                this.isFinished = value;
                this.RaisePropertyChanged();
            }
        }

        public int Progress
        {
            get => this.progress;
            set
            {
                this.progress = value;
                this.RaisePropertyChanged();
            }

        }

        public void OnProgressReported(long dummyval)
        {
            this.Progress = (int) dummyval;
        }

        public void OnLongTaskFinished()
        {
            this.IsFinished = true;
        }
    }
}

答案 1 :(得分:1)

import tkinter as tk    
root = tk.Tk()    
myLabel= tk.Label(root, text="Click Me", cursor="hand2")
myLabel.pack()    
root.mainloop()

答案 2 :(得分:0)

要快速预览可用光标:

(取自https://www.tcl.tk/man/tcl8.4/TkCmd/cursors.htm

import tkinter as tk

root = tk.Tk()

frame = tk.Frame(root)
frame.pack(expand=True, fill=tk.BOTH)

cursors = """
X_cursor
arrow
based_arrow_down
based_arrow_up
boat
bogosity
bottom_left_corner
bottom_right_corner
bottom_side
bottom_tee
box_spiral
center_ptr
circle
clock
coffee_mug
cross
cross_reverse
crosshair
diamond_cross
dot
dotbox
double_arrow
draft_large
draft_small
draped_box
exchange
fleur
gobbler
gumby
hand1
hand2
heart
icon
iron_cross
left_ptr
left_side
left_tee
leftbutton
ll_angle
lr_angle
man
middlebutton
mouse
pencil
pirate
plus
question_arrow
right_ptr
right_side
right_tee
rightbutton
rtl_logo
sailboat
sb_down_arrow
sb_h_double_arrow
sb_left_arrow
sb_right_arrow
sb_up_arrow
sb_v_double_arrow
shuttle
sizing
spider
spraycan
star
target
tcross
top_left_arrow
top_left_corner
top_right_corner
top_side
top_tee
trek
ul_angle
umbrella
ur_angle
watch
xterm""".split()

i = 0
j = 0
for cur in cursors:
    if i == 20:
        i = 0
        j += 1
    tk.Button(frame, text=cur, height=2, width=15, cursor=cur).grid(row=i, column=j)
    i += 1

tk.mainloop()