如何使鼠标事件传播到`scroll`容器中的小部件? [英] How to make mouse events propagate to widgets in `scroll` containers?

查看:80
本文介绍了如何使鼠标事件传播到`scroll`容器中的小部件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我知道,在官方文档中它说

So I know that on the official documentation it says


请注意,鼠标事件不会传播到滚动容器内部的小部件。

Please note that mouse events do not propagate to widgets inside of the scroll container.

但是我要做的正是:我如何使鼠标事件通过此小部件传播?有办法吗?

But what I'm trying to do is exactly that: How can I make mouse events propagate through this widget? Is there a way?

我要做的是制作一个内置的待办应用。但是为此,我实际上需要有一些物品(这是我要完成的任务)

What I'm trying to do is make a "to-do app" built into awesome. But for that I actually need to have items (which will be the tasks I want to get done)

所以我想要一个菜单​​,其中包含行的小部件,这样我就可以用它来用鼠标滚轮(或键盘)上下滚动,但仍然可以选择东西。我想我可以通过设置小部件的按钮并使用 scroll 容器的<$ c进行鼠标滚动$ c>:暂停,:继续等方法,但是我无法执行点击操作。

So I want to have a menu with widgets inside it that are rows, so that I can use it to scroll with the mouse wheel (or the keyboard) up and down, but still be able to select stuff. I think I can do the scrolling with the mouse through setting the widget's buttons and tweaking with the scroll container's :pause, :continue, etc. methods but I can't do the clicking part.

因此,我的问题是:我该怎么做?即使不是通过使用 scroll 容器,我该如何进行这项工作?

Therefore, my question is: how can I accomplish this? even if it's not through using the scroll container, how can I make this work?

要了解我想要的是我到目前为止所做的:

To get an idea of what I want, here's what I made so far:

推荐答案

好的,因此,您需要一个复杂的版本,该版本可以将其包含的窗口小部件裁剪到其大小,并且还可以处理输入事件。以下是复杂而缓慢的版本:

Okay, so you want the complicated version that will clip its contained widget to its size and also handle input events. The following is the complicated and slow version:

local inner_widget = screen[1].mytaglist
local inner_width, inner_height = 200, 40
-- No idea how to pick a good width and height for the wibox.
local w = wibox{ x = 100, y = 100, width = 100, height = 20, visible = true }
local own_widget = wibox.widget.base.make_widget()
w:set_widget(own_widget)
local offset_x, offset_y = -20, 0
local own_context = { screen = screen[1], dpi = 92 } -- We have to invent something here... :-(
local hierarchy
hierarchy = wibox.hierarchy.new(own_context, inner_widget, inner_width, inner_height, function()
    own_widget:emit_signal("widget::redraw_needed")
end, function()
    hierarchy:update(own_context, inner_widget, inner_width, inner_height)
    own_widget:emit_signal("widget::redraw_needed")
end, nil)
function own_widget:draw(context, cr, width, height)
    -- This does the scrolling
    cr:translate(offset_x, offset_y)

    -- Then just draw the inner stuff directly
    hierarchy:draw(own_context, cr)
end
-- Start a timer to simulate scrolling: Once per second we move things slightly
gears.timer.start_new(1, function()
    offset_x = - offset_x
    own_widget:emit_signal("widget::redraw_needed")
    return true
end)
-- Finally, make input events work
local function button_signal(name)
    -- This function is basically copy&paste from find_widgets() in
    -- wibox.drawable
    local function traverse_hierarchy_tree(h, x, y, ...)
        local m = h:get_matrix_from_device()

        -- Is (x,y) inside of this hierarchy or any child (aka the draw extents)?
        -- If not, we can stop searching.
        local x1, y1 = m:transform_point(x, y)
        local x2, y2, w2, h2 = h:get_draw_extents()
        if x1 < x2 or x1 >= x2 + w2 then
            return
        end
        if y1 < y2 or y1 >= y2 + h2 then
            return
        end
        -- Is (x,y) inside of this widget?
        -- If yes, we have to emit the signal on the widget.
        local width, height = h:get_size()
        if x1 >= 0 and y1 >= 0 and x1 <= width and y1 <= height then
            h:get_widget():emit_signal(name, x1, y1, ...)
        end
        -- Continue searching in all children.
        for _, child in ipairs(h:get_children()) do
            traverse_hierarchy_tree(child, x, y, ...)
        end
    end
    own_widget:connect_signal(name, function(_, x, y, ...)
        -- Translate to "local" coordinates
        x = x - offset_x
        y = y - offset_y
        -- Figure out which widgets were hit and emit the signal on them
        traverse_hierarchy_tree(hierarchy, x, y, ...)
    end)
end
button_signal("button::press")
button_signal("button::release")

而不是让AwesomeWM处理一切并将另一个小部件放置在:layout 中,此代码本身会执行更多操作。即,它直接管理窗口小部件树(在AwesomeWM中称为层次结构)并对其进行绘制。然后,这段代码的一半负责处理按钮事件:传入代码后,此代码会将其滚动到正确的小部件,同时考虑到当前的滚动。

Instead of letting AwesomeWM handle everything and just placing another widget in :layout, this code does more itself. Namely, it directly manages a widget tree (called a "hierarchy" in AwesomeWM) and draws it itself. Half of this code is then responsible for handling button events: When one comes in, this code forwards it to the right widget, taking the current scrolling into account.

每当发生任何更改时,这都会重绘此自定义小部件显示的所有内容。我想对于您的滚动问题来说还是有必要的,因为滚动一点时一切都会改变。但是,当AwesomeWM自己绘制一些小部件时,它将尝试仅重绘实际更改的部分。例如,如果由于时间更改而导致时钟更新,则只有时钟会被重绘。而是始终在这里重绘所有内容。

Note that this redraws everything that is shown by this custom widget whenever anything changes. I guess for your scrolling problem this is necessary anyway, because "everything changes" when you scroll a bit. However, when AwesomeWM draws some widgets itself, it tries to only redraw the part that actually changed. For example, if the clock updates because the time changed, only the clock will be redrawn. This code here instead redraws everything always.

(是的,我知道这段代码是意大利面条式的,很糟糕,但是它应该可以帮助您找出必要的成分)

(And yes, I know that this code is quite spaghetti-y and bad, but it should help you figure out the necessary ingredients.)

这篇关于如何使鼠标事件传播到`scroll`容器中的小部件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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