Pyside的选中和焦点
- focus焦点,  哪个item现在吃键盘输入
    
QGraphicsScene::focusItem()返回它- 最好交给系统自动维护, 系统有(微弱)默认样式
 - 一个或没有(nullptr), 可以用来判断当前是否输入状态,
        
- 系统自动维护他, 比如点击空白, scene就会清掉他.
 
 
 - selected选中, 哪个 item 高亮
    
- item.isSelected()
返回true - 同一时间可以 N 个(框选一堆)
 - 只能自己维护, 系统没有默认样式
 
 - item.isSelected()
 
基本概念
- QGraphicsItemGroup切换show/hide时, 不会处理焦点.
 - QGraphicsScene 只允许一个焦点项(focusItem() 返回单一项), 焦点项会自动失焦.
 
各自的生命周期
| 动作 | 是否改 focus | 是否改 selected | 备注 | 
|---|---|---|---|
| 鼠标左键点 item | ✅ 变成焦点 | ❌ 不改(除非你代码里 setSelected) | 
      焦点自动转移 | 
| 鼠标中键/右键点 item | ❌ 不改焦点 | ❌ 不改选中 | 完全无影响 | 
| 橡皮筋框选 | ❌ 不改焦点 | ✅ 把框内 item 设 selected | 焦点仍留在旧 item | 
| 按空格开始编辑 | ✅ 焦点不变 | ✅ 通常把该 item 也设 selected | 自己代码联动 | 
| 点空白区(默认) | ✅ Scene 清掉焦点 | ❌ 不改选中 | 出现“无焦点但有选中” | 
代码 item->setSelected(true) | 
      ❌ 不改焦点 | ✅ 选中位变 | 需要你自己补 setFocusItem 才联动 | 
    
代码 scene->setFocusItem(item) | 
      ✅ 焦点变 | ❌ 不改选中 | 需要你自己补 setSelected 才联动 | 
    
状态处理
我明白了, 判断编辑状态就在focusitemchange就可以了, 但是, 选中状态其实这么干没用, 因为一定要自己维护, 所以应该分散在键盘鼠标的处理事件中, 先scene.clearSelection() 一键清空所有选中位, 然后再item.setSelected(bool)
scene.clearSelection() + item.setSelected(bool) 这个流程其实不如自己手动维护一个选中的状态item引用方便. 自己维护一个currentitem=xxx
# 编辑状态处理
注册处理事件: scene.focusItemChanged(QGraphicsItem *new, QGraphicsItem *old, Qt::FocusReason) 
状态判断依据: scene.focusItem()
# 更简洁的方案, 自己维护一个当前选中项目
current=xxx
# 选中状态处理 传统的不合适的方案
scene.clearSelection() 一键清空所有选中位(不会动焦点) 
item.setSelected(bool)
想让对象「可被选」必须加:  item.setFlag(QGraphicsItem::ItemIsSelectable, True)
api参考
一、选中(Selection)——“谁被高亮”
- 状态位
    
item.isSelected() -> boolitem.setSelected(bool)
 - Scene 级查询
    
scene.selectedItems() -> QList<QGraphicsItem*>当前所有被选中的对象scene.selectionArea() -> QPainterPath返回最近一次框选的路径(橡皮筋)scene.clearSelection()一键清空所有选中位(不会动焦点)
 - 程序式框选
    
scene.setSelectionArea(QPainterPath, transform)用任意路径批量选/取消scene.setSelectionArea(path, Qt::ReplaceSelection, ...)可加模式参数
 - 必备标志
    
- 想让对象「可被选」必须加: item.setFlag(QGraphicsItem::ItemIsSelectable, True)
 
 - 信号
    
scene.selectionChanged()每次选中集合变化时触发(含增/减)
 
二、焦点(Focus)——“谁吃键盘”
- 状态位
    
item.hasFocus() -> bool当前是否拥有键盘焦点- 重要
scene.focusItem() -> QGraphicsItem*整个场景里谁在吃键盘(可为空) - 没意义
scene.hasFocus() -> bool场景本身是否拥有输入焦点(View 焦点) 
 - 设置/拿走
    
scene.setFocusItem(item, reason)强塞焦点(item 需ItemIsFocusable)scene.setFocus(reason)让场景自己拿焦点(不指定 item)scene.clearFocus()场景放弃焦点(focusItem 变空)
 - 必备标志
    
- 想让对象「可被给焦点」:  
item.setFlag(QGraphicsItem::ItemIsFocusable, True) 
 - 想让对象「可被给焦点」:  
 - 焦点保护(Qt 5.12+)
    
scene.setStickyFocus(True)禁止“点空白”自动清焦点(焦点不会掉空)
 - 信号
    
scene.focusItemChanged(QGraphicsItem *new, QGraphicsItem *old, Qt::FocusReason)
每次焦点移动都会发,方便你“视觉选中”跟它同步。
 
三、最常用“对齐”模板(放在 NavManager 或点击事件里)
def pick_new_current(self, item):
    # 1. 焦点搬家
    self.scene.setFocusItem(item, Qt.MouseFocusReason)
    # 2. 选中搬家(先清旧集合,可只清自己)
    for i in self.scene.selectedItems():
        i.setSelected(False)
    item.setSelected(True)
四、调试小技巧
- 
    
打印焦点链
print("focus:", self.scene.focusItem(), "selected:", self.scene.selectedItems()) - 
    
焦点丢失追踪
连接scene.focusItemChanged信号,在槽里断点或日志,一眼看出谁把焦点抢走了。