Qt5中QML自定义环形菜单/环形选择框的实现

Qt5 中本身提供了扇形菜单 PieMenu,属于 QtQuick.Extras 模块,这个模块是拓展自 QtQuick.Control1 的,QtQuick.Control1 在 Qt5 高版本被废弃,并在 Qt6 移除。

不过我们也可以用 QtQuick.Control2 的组件自定义样式来实现环形或扇形的菜单和选择框。主要思路就是使用 PathView 来替换默认的 ListView,再改下弹框的背景样式。

ItemDelegate 需要设置给 ComboBox 或者 Menu,而不是 View。最好用 Button 的相关类型(默认是 ItemDelegate 类型),因为组件默认这些小部件是 Button 类型,内部 cast 成按钮来处理的。而且用按钮就不用自己处理下拉框 currentIndex,内部会自己处理,这也避免了我们在这个 delegate 对 currentIndex赋值后导致其属性绑定失效的问题。

QQuickAction *QQuickMenu::actionAt(int index) const
{
  Q_D(const QQuickMenu);
  QQuickAbstractButton *item = qobject_cast<QQuickAbstractButton *>(d->itemAt(index));
  if (!item)
      return nullptr;

  return item->action();
}

自定义的时候遇到一点状况,就是 PathView 替代 ListView 作为 Menu 的 contentItem 后,Menu 的 contentData 和 contentModel 始终会多一个表示高亮的 Item,这样环形路径就有个缺口,目前我只能将显示的 Item 个数减去一个来使显示效果正常。

    contentItem: PathView {
      model: control.contentModel
      //把PathView放Menu,会有一个高亮Item被放到contentModel,减去
      pathItemCount: control.count > 0 ? control.count - 1 : 0
      //... ...
  }

Demo 链接:https://github.com/gongjianbo/MyTestCode2021/tree/master/Qml/TestQml_20220313_PathView

主要代码:

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window {
  width: 640
  height: 480
  visible: true
  title: qsTr("PathView")

  Row {
      anchors.centerIn: parent
      spacing: 20

      MyComboBox {
          model: 10
      }

      Button {
          width: 60
          height: 30
          text: "menu"
          background: Rectangle {
              radius: 15
              color: "red"
              border.color: "black"
          }
          onClicked: {
              menu.popup()
          }

          MyMenu {
              id: menu
              anchors.centerIn: parent
              Action { text: "1" }
              Action { text: "2" }
              Action { text: "3" }
              Action { text: "4" }
              Action { text: "5" }
              Action { text: "6" }
              Action { text: "7" }
              Action { text: "8" }
              Action { text: "9" }
              Action { text: "10" }
          }
      }
  }
}
import QtQuick 2.12
import QtQuick.Controls 2.12

//环形选择框
//龚建波 2022-03-13
//note:弹框为pop会被限制在window内
ComboBox {
  id: control

  implicitWidth: 30
  implicitHeight: 30
  opacity: 0.9999

  delegate: ItemDelegate {
      width: 30
      height: width
      padding: 0
      background: Rectangle {
          radius: width / 2
          color: "green"
          border.color: "black"
      }
      contentItem: Text {
          text: modelData
          padding: 0
          verticalAlignment: Text.AlignVCenter
          horizontalAlignment: Text.AlignHCenter
      }
  }
  contentItem: Text {
      text: control.displayText
      padding: 0
      verticalAlignment: Text.AlignVCenter
      horizontalAlignment: Text.AlignHCenter
  }
  indicator: null
  background: Rectangle {
      radius: 15
      color: "green"
      border.color: "black"
  }
  popup: Popup {
      id: pop
      width: 200
      height: width
      anchors.centerIn: parent
      margins: 0
      padding: 0
      //pathview环形的角度范围和延申半径
      property int angle: 1
      property int spread: 1
      //pop弹出和隐藏时的过渡动画
      enter: Transition {
          ParallelAnimation {
              NumberAnimation { property: "angle"; from: 1; to: 360; duration: 500 }
              NumberAnimation { property: "spread"; from: 1; to: 100; duration: 500 }
          }
      }
      exit: Transition {
          ParallelAnimation {
              NumberAnimation { property: "angle"; from: 360; to: 1; duration: 500 }
              NumberAnimation { property: "spread"; from: 100; to: 1; duration: 500 }
          }
      }
      background: Item { }
      contentItem: PathView {
          model: control.popup.visible ? control.delegateModel : null
          //currentIndex: control.highlightedIndex
          //highlightRangeMode: PathView.NoHighlightRange
          interactive: false
          path: Path {
              //一个圆环路径
              PathAngleArc {
                  centerX: 100; centerY: 100
                  radiusX: pop.spread; radiusY: pop.spread
                  moveToStart: true
                  startAngle: 0
                  sweepAngle: pop.angle
              }
          }
      }
  }
}
import QtQuick 2.12
import QtQuick.Controls 2.12

//环形菜单
//龚建波 2022-03-13
//note:弹框为pop会被限制在window内
Menu {
  id: control

  implicitWidth: 250
  implicitHeight: 250
  margins: 0
  padding: 0

  //pathview环形的角度范围和延申半径
  property int angle: 1
  property int spread: 1
  //pop弹出和隐藏时的过渡动画
  enter: Transition {
      ParallelAnimation {
          NumberAnimation { property: "angle"; from: 1; to: 360; duration: 500 }
          NumberAnimation { property: "spread"; from: 1; to: 100; duration: 500 }
      }
  }
  exit: Transition {
      ParallelAnimation {
          NumberAnimation { property: "angle"; from: 360; to: 1; duration: 500 }
          NumberAnimation { property: "spread"; from: 100; to: 1; duration: 500 }
      }
  }
  delegate: MenuItem {
      id: item
      width: 30
      height: width
      padding: 0
      spacing: 0
      indicator: null
      arrow: null
      background: Rectangle {
          radius: width / 2
          color: "red"
          border.color: "black"
      }
      contentItem: Text {
          text: item.text
          padding: 0
          verticalAlignment: Text.AlignVCenter
          horizontalAlignment: Text.AlignHCenter
      }
  }
  contentItem: PathView {
      implicitWidth: 250
      implicitHeight: 250
      model: control.contentModel
      //把PathView放Menu,会有一个高亮Item被放到contentModel,减去
      pathItemCount: control.count > 0 ? control.count - 1 : 0
      //currentIndex: control.currentIndex
      //highlightRangeMode: PathView.NoHighlightRange
      interactive: false
      path: Path {
          //一个圆环路径
          PathAngleArc {
              centerX: 125; centerY: 125
              radiusX: control.spread; radiusY: control.spread
              moveToStart: true
              startAngle: 0
              sweepAngle: control.angle
          }
      }
  }
  background: Item { }
}

关于Qt5中QML自定义环形菜单/环形选择框的实现的文章就介绍至此,更多相关Qt5 QML环形菜单内容请搜索编程教程以前的文章,希望以后支持编程教程

C++编写的一个图书管理系统,供大家参考。2018大一的课设,搬到这纪念一下,共1200多行代码为图书管理人员编写一个图书管理系统,图书管理系统的设计主要是实现对图书的管理和相关操作,包括3个表:图书信息表 ...