Skip to content

优化看漫画时最大最小化闪烁 #229

Description

@lkyxgh

窗口最小化恢复时图片闪烁修复

问题现象

阅读漫画时,窗口最小化再恢复,图片会先消失 ~0.5s(中间显示页码文字),然后才重新出现。

根因分析

  1. DeviceCoordinateCache — 缓存在设备像素级别,窗口最小化时设备上下文被销毁,所有 item 缓存失效。
  2. MinimalViewportUpdate — 最小化恢复后不立即标记整个视口为脏区,重绘延迟。
  3. ResetSize → ChangeReadMode2 → allItemsState.clear() — 窗口事件触发 ResetSize,调用 ChangeReadMode2 清掉图片加载状态后,PixmapToLabel 把已缓存的图片替换成页码文字,造成「原图 → 页码 → 原图」的闪烁链。

修改文件

src/view/read/read_graphics.py,共 5 处改动:


改动 1:DeviceCoordinateCacheItemCoordinateCache(4 处)

ItemCoordinateCache 缓存在逻辑坐标级别,不受设备上下文销毁影响。

位置 1 — InitHelp,滚动模式 label pool:

                 self.graphicsScene.addItem(proxy)
-                proxy.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
+                proxy.setCacheMode(QGraphicsItem.ItemCoordinateCache)

位置 2 — InitReadMode,左右/等宽模式:

             self.graphicsItem1.setCacheMode(
-                QGraphicsItem.DeviceCoordinateCache
+                QGraphicsItem.ItemCoordinateCache
             )

位置 3+4 — InitReadMode,双页模式:

             self.graphicsItem1.setCacheMode(
-                QGraphicsItem.DeviceCoordinateCache
+                QGraphicsItem.ItemCoordinateCache
             )
             self.graphicsItem2.setCacheMode(
-                QGraphicsItem.DeviceCoordinateCache
+                QGraphicsItem.ItemCoordinateCache
             )

改动 2:MinimalViewportUpdateSmartViewportUpdate

-        self.setViewportUpdateMode(QGraphicsView.MinimalViewportUpdate)
+        self.setViewportUpdateMode(QGraphicsView.SmartViewportUpdate)

Smart 模式能正确判断窗口状态变化后该重绘什么。


改动 3:新增 showEvent 强制即时重绘

ReadGraphicsView 类中新增,窗口恢复时不等事件循环调度,立即刷新视口:

+    def showEvent(self, event):
+        """窗口恢复显示时强制立即重绘视口,避免闪烁"""
+        super().showEvent(event)
+        self.viewport().update()

改动 4:__init__ 新增尺寸追踪变量

         self.initReadMode = None
+        self._lastWidth = None
+        self._lastHeight = None

改动 5:重写 ResetSize — 区分最小化恢复 vs 真正 resize

之前的实现把一切窗口事件都走重量级 ChangeReadMode2(清空状态→重建),现在按尺寸是否变化分流:

     def ResetSize(self):
-        self.qtTool.ChangeReadMode2(self.readImg.stripModel.value, keepScale=True)
+        if not self.initReadMode:
+            return
+        w, h = self.width(), self.height()
+        # 最小化后恢复 — 尺寸不变,只刷新视口
+        if w == self._lastWidth and h == self._lastHeight:
+            self.viewport().update()
+            return
+        # 尺寸确实变了 — 重算位置 + 重新渲染图片
+        self._lastWidth, self._lastHeight = w, h
+        maxNum = self.maxPic
+        if ReadMode.isScroll(self.initReadMode):
+            self.ResetLabelSize(maxNum)
+            for index, proxy in enumerate(self.allItems):
+                value = self.labelSize.get(index)
+                if self.initReadMode == ReadMode.UpDown:
+                    proxy.setPos(0, value / self.devicePixelRatioF())
+                else:
+                    proxy.setPos(value / self.devicePixelRatioF(), 0)
+        elif ReadMode.isDouble(self.initReadMode):
+            self.graphicsItem2.setPos(self.width() // 2, 0)
+        self.ResetMaxNum()
+        self.readImg.ShowImgAll()

效果

  • 最小化恢复:尺寸未变 → 仅 viewport().update(),不重建任何资源,无闪烁。
  • 真正 resize:尺寸变化 → 重算位置 + ShowImgAll() 以新尺寸重渲染图片,图片正确适配。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions