【发布时间】:2012-11-15 14:45:29
【问题描述】:
在访问类变量(Qt::Actions 的数组)时,我遇到了分段错误问题,我一直在尝试将其缩减为复制该问题的最小代码示例:
#!/usr/bin/ruby
require 'Qt4'
require 'rufus/scheduler'
app = Qt::Application.new(ARGV)
class ManagerWidget < Qt::Widget
signals 'changed(int)'
def initialize
super(nil)
max_index = 2
next_index = 0
scheduler = Rufus::Scheduler.start_new
scheduler.every '10s' do
emit changed(next_index)
if next_index < max_index - 1
next_index += 1
else
next_index = 0
end
end
end
end
class Tray < Qt::Widget
def initialize
super(nil)
tray = Qt::SystemTrayIcon.new
manager_widget = ManagerWidget.new
menu = Qt::Menu.new
tray_icon = Qt::Icon.new("./icons/Gnome-Preferences-Desktop-Wallpaper-64.png")
actions = []
manager_widget.connect(SIGNAL('changed(int)')) do |i|
puts "changed #{i}"
actions[i].text = '...' if actions && actions[i]
end
2.times do |i|
sub_menu = Qt::Menu.new("#{i + 1}")
actions[i] = sub_menu.add_action('x')
menu.add_menu(sub_menu)
end
tray.icon = tray_icon
tray.context_menu = menu
tray.show
end
end
Tray.new
app.exec
以上代码输出:
"sni-qt/12147" WARN 14:35:48.326 void StatusNotifierItemFactory::connectToSnw() Invalid interface to SNW_SERVICE
changed 0
changed 1
changed 0
changed 1
changed 0
changed 1
changed 0
changed 1
./min-code-example.rb:42: [BUG] Segmentation fault
ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]
[... snipped due to character limits on posting ...]
[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html
Aborted (core dumped)
Failed (134)
似乎有必要使用子菜单来触发此问题 - 至少将操作添加到托盘菜单本身运行了很长时间没有问题(我将其放置了 10 倍以上用上面的代码得到了错误)。
Ruby 版本:ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]
Qt 版本:4.8.1
绑定版本:qtbindings (4.8.3.0)
Linux 版本:Ubuntu 12.04
另一个奇怪的行为是 puts 调用的输出有时会立即显示在控制台中,有时它只会在我将鼠标悬停在托盘图标上时打印。
我什至不知道从哪里开始跟踪这个问题,所以非常感谢您提供的任何意见。
更新:我已经离开了一段时间,因为我无法进一步了解。我试图重新开始,但我仍然遇到同样的问题。我对这个问题进行了更深入的研究,因为它说'missing_method',所以我首先打印了这个类,以确保我确实在查看 Qt::Action(我是),然后根据哪些方法可用actions[0].methods.
.methods 输出:
[:setShortcut, :shortcut=, :qobject_cast, :inspect, :pretty_print, :className,
:class_name, :inherits, :findChildren, :find_children, :findChild, :find_child,
:connect, :method_missing, :const_missing, :dispose, :isDisposed, :disposed?,
:qVariantValue, :qVariantFromValue, :**, :+, :~, :-@, :-, :*, :/, :%, :>>,
:<<, :&, :^, :|, :<, :<=, :>, :>=, :==, :is_a?, :kind_of?, :methods,
:protected_methods, :public_methods, :singleton_methods, :qDebug, :qFatal,
:qWarning, :SIGNAL, :SLOT, :emit, :QT_TR_NOOP, :QT_TRANSLATE_NOOP, :nil?, :===,
:=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup,
:initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust,
:untrusted?, :trust, :freeze, :frozen?, :to_s, :private_methods,
:instance_variables, :instance_variable_get, :instance_variable_set,
:instance_variable_defined?, :instance_of?, :tap, :send, :public_send,
:respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method,
:define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=,
:instance_eval, :instance_exec, :__send__, :__id__, "blockSignals", "children",
"connect", "deleteLater", "disconnect", "dumpObjectInfo", "dumpObjectTree",
"dynamicPropertyNames", "event", "eventFilter", "inherits", "installEventFilter",
"widgetType?", "killTimer", "metaObject", "moveToThread", "objectName", "parent",
"property", "qt_metacall", "qt_metacast", "removeEventFilter", "objectName=",
"parent=", "setProperty", "setUserData", "signalsBlocked", "startTimer",
"thread", "userData", "actionGroup", "activate", "associatedGraphicsWidgets",
"associatedWidgets", "autoRepeat", "data", "font", "hover", "icon", "iconText",
"checkable?", "checked?", "enabled?", "iconVisibleInMenu?", "separator?",
"visible?", "menu", "menuRole", "parentWidget", "priority", "actionGroup=",
"autoRepeat=", "checkable=", "checked=", "data=", "disabled=", "enabled=",
"font=", "icon=", "iconText=", "iconVisibleInMenu=", "menu=", "menuRole=",
"priority=", "separator=", "shortcut=", "shortcutContext=", "shortcuts=",
"softKeyRole=", "statusTip=", "text=", "toolTip=", "visible=", "whatsThis=",
"shortcut", "shortcutContext", "shortcuts", "showStatusText", "softKeyRole",
"statusTip", "text", "toggle", "toolTip", "trigger", "whatsThis"]
在这种情况下,当发生分段错误时,我试图执行actions[0].enabled = true,据我所知,这是在输出中(从底部算起的第 6 行,enabled=)。我还尝试了setEnabled(true)、set_enabled(true) 以及我能想到的任何东西。
即使在操作对象上调用inspect 也会导致分段错误,尽管在最初将操作放入数组的循环中执行此操作是可以的。我真的不明白这是哪里出了问题。
编辑:作为对使用QTimer 的建议的回应,我尝试了这个,但我仍然遇到同样的问题。该代码目前比上面列出的要复杂一些,所以我将在这里编写一些快速的伪代码来说明流程:
def init_tray
actions = []
2.times do |i|
actions[i] = ... # init and add to systray, store reference in array
end
update = Proc.new do |i|
actions[i].setText('...') # update the text on one of the actions defined above
end
listener = ... # create a listener that can be called by Manager on certain events - will call the update Proc among other things.
manager = Manager.new(..., listener)
end
对 Manager.new 的调用初始化该对象,并在最后调用具有状态更改的侦听器,这反过来又调用访问 actions 数组的 update Proc。在这个阶段这应该都在同一个线程中,除了Qt::Action 的实际创建之外,这些行都不依赖于QT。我已经删除了 Rufus 调度并将其替换为 QTimer,但它还远远没有解决这个问题。
【问题讨论】:
-
你确定你可以像这样使用 qtbindings 吗? qtbindings 是线程安全的吗?你知道 Rufus 创建了一个新的 Ruby 线程吗?我认为一旦你进入 Qt 世界,你需要使用 Qt 计时器而不是 Ruby 计时器。 IE。要触发
emit,您可能需要使用QTimer之类的东西而不是Rufus。 -
@Casper,我不知道,我不知道 Rufus 创建了一个新的 Ruby 线程,不。即使它不是线程安全的,它似乎仍然是一种非常奇怪的失败方式(仍然只有一个线程可以随时访问它,并且参考似乎没问题,因为我可以打印出一些关于它的信息)。我还在努力学习 QT,并没有意识到我可以使用 QTimer,我会试一试,谢谢。
-
@Casper 毕竟这似乎不是问题,Rufus 调度程序根本没有运行失败的代码(因为它在初始化期间失败,它仍然应该是主线程) .如果这有助于澄清,我已经在问题中添加了一些关于它的更多细节。
-
我不知道这是否相关,但似乎我的 Widget 的
initialize方法被执行了两次。我不知道是什么原因造成的,或者为什么。我当然在我自己的代码中找不到任何对它的引用。
标签: ruby segmentation-fault qtruby