Evgenii Legotckoi
02 березня 2018 р. 13:53

Android. Java проти Qt QML - Підручник 004. Створення меню на панелі дій з підменю

Отже, продовжуємо реалізовувати однаковий функціонал у додатках під Android із двох принципово різних світів. А саме на традиційній Java і менш поширеній Qt QML C++.

На цей раз реалізуємо меню в ActionBar активіті. Зазначу, що ActionBar для варіанта з QML доведеться писати самостійно, оскільки такого елемента Qt QML немає, але він реалізується через компонент ToolBar. Оскільки цей момент був описаний в уроці про Hello World , то в даному уроці ретельно зупинятися на ньому не будемо, тільки винесемо ActionBar в окремий файл QML, зробивши його окремим типом QML і додамо до нього іконку меню, за натисканням на яку викликатимемо меню.

Меню буде наступною структурою:

  • Інформація
  • Перший
  • Другий
  • Про

У центрі вікна програми повинен бути текст, який замінюватиметься іншим текстом при натисканні наступних пунктів меню

  • Спочатку
  • Другий
  • Про

Зовнішній вигляд меню на Java

Перший рівень

Другий рівень

Зовнішній вигляд меню на Qt QML

Перший рівень

Другий рівень

Реалізація JAVA

menu.xml

Для верстки меню необхідно створити XML файл, який розташовуватиметься в ресурсному каталозі menu. Так і назвемо його menu.xml

Тут все досить просто, є невелика верстка з назвами пунктів меню, вкладеними елементами та id, якими можна буде звернутися до даних пунктів з Java коду.

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <menu xmlns:app="http://schemas.android.com/apk/res-auto"
  3. xmlns:android="http://schemas.android.com/apk/res/android">
  4.  
  5. <item
  6. android:id="@+id/informationItem"
  7. android:title="Information">
  8. <menu>
  9. <item
  10. android:id="@+id/firstInfoItem"
  11. android:title="First" />
  12. <item
  13. android:id="@+id/secondInfoItem"
  14. android:title="Second" />
  15. </menu>
  16. </item>
  17. <item
  18. android:id="@+id/aboutItem"
  19. android:title="About" />
  20. </menu>

activity_main.xml

Далі йде верстка самої активіті, яка в даному випадку створена за умовчанням.

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context="com.evileg.javamenu.MainActivity">
  8.  
  9. <TextView
  10. android:id="@+id/textView"
  11. android:layout_width="wrap_content"
  12. android:layout_height="wrap_content"
  13. android:text="Hello World!"
  14. app:layout_constraintBottom_toBottomOf="parent"
  15. app:layout_constraintLeft_toLeftOf="parent"
  16. app:layout_constraintRight_toRightOf="parent"
  17. app:layout_constraintTop_toTopOf="parent" />
  18.  
  19. </android.support.constraint.ConstraintLayout>

MainActivity.java

А тепер потрібно ініціалізувати всі компоненти меню та навішувати на них обробник події кліка.

  1. package com.evileg.javamenu;
  2.  
  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.view.Menu;
  6. import android.view.MenuItem;
  7. import android.widget.TextView;
  8.  
  9. public class MainActivity extends Activity {
  10.  
  11. // Объявим объекты всех пунктов меню
  12. MenuItem aboutItem;
  13. MenuItem firstInfoItem;
  14. MenuItem secondInfoItem;
  15.  
  16. // А также текстового поля, в которое будем устанавливать текст
  17. TextView textView;
  18.  
  19. @Override
  20. protected void onCreate(Bundle savedInstanceState) {
  21. super.onCreate(savedInstanceState);
  22. setContentView(R.layout.activity_main);
  23. textView = findViewById(R.id.textView); // найдём данное текстовое поле в ресурсах
  24. }
  25.  
  26. // Создадим обработчики пунктов меню
  27. @Override
  28. public boolean onCreateOptionsMenu(Menu menu) {
  29. getMenuInflater().inflate(R.menu.menu, menu);
  30.  
  31. // Найдём все элементы пунктов меню
  32. aboutItem = menu.findItem(R.id.aboutItem);
  33. firstInfoItem = menu.findItem(R.id.firstInfoItem);
  34. secondInfoItem = menu.findItem(R.id.secondInfoItem);
  35.  
  36. // Создадим обработчик кликов по пунктам меню
  37. MenuItem.OnMenuItemClickListener onMenuClickListener = new MenuItem.OnMenuItemClickListener() {
  38. @Override
  39. public boolean onMenuItemClick(MenuItem item) {
  40. switch (item.getItemId()) {
  41. case R.id.aboutItem:
  42. textView.setText("About Menu Item is pressed");
  43. break;
  44. case R.id.firstInfoItem:
  45. textView.setText("First Info Item is pressed");
  46. break;
  47. case R.id.secondInfoItem:
  48. textView.setText("Second Info Item is pressed");
  49. break;
  50. }
  51. return true;
  52. }
  53. };
  54.  
  55. // Установим этот обработчик на пункты меню
  56. aboutItem.setOnMenuItemClickListener(onMenuClickListener);
  57. firstInfoItem.setOnMenuItemClickListener(onMenuClickListener);
  58. secondInfoItem.setOnMenuItemClickListener(onMenuClickListener);
  59.  
  60. return true;
  61. }
  62. }

Реалізація Qt QML

ActionBar.qml

Я створив спеціальний тип ActionBar в окремому файлі QML, щоб виділити його з основного файлу main.qml. Це дозволить відокремити цей код від решти корисної частини коду, яка має показати відмінність реалізацій меню на Java та Qt QML. Також цей ActionBar буде використовуватися в наступних статтях.

Зверніть увагу на сигнал menuClicked , цей сигнал буде викликатись у ActionBar, коли користувач натисне пальцем на MouseArea, яка відповідає за клік по нашій кастомній кнопці меню. За цим сигналом буде відкрито меню, розташоване у файлі main.qml

  1. import QtQuick 2.10
  2. import QtQuick.Controls 2.3
  3. import QtQuick.Controls.Material 2.1
  4.  
  5. ToolBar {
  6. id: root
  7. height: 48
  8.  
  9. signal menuClicked() // Сигнал, который сообщит о клике по кнопке меню
  10.  
  11. Rectangle {
  12. anchors.fill: parent
  13. color: "#080808"
  14.  
  15. Image {
  16. id: ico
  17. height: 36
  18. width: 36
  19. anchors {
  20. left: parent.left
  21. leftMargin: 10
  22. top: parent.top
  23. topMargin: 6
  24. }
  25. source: "qrc:/icons/ic_launcher.png"
  26. }
  27.  
  28.  
  29. Text {
  30. anchors {
  31. verticalCenter: parent.verticalCenter
  32. left: ico.right
  33. leftMargin: 4
  34. }
  35.  
  36. text: qsTr("QMLMenu")
  37. font.pixelSize: 18
  38. color: "white"
  39. }
  40.  
  41.   // Начало реализации кнопки меню
  42. Rectangle {
  43. width: height
  44. color: menuArea.pressed ? "#55ffffff" : "transparent"
  45. anchors {
  46. top: parent.top
  47. right: parent.right
  48. bottom: parent.bottom
  49. }
  50.  
  51. Image {
  52. id: menuIcon
  53. height: 36
  54. width: 36
  55. anchors {
  56. centerIn: parent
  57. }
  58.  
  59. source: "qrc:/icons/menu.png"
  60. }
  61.  
  62. MouseArea {
  63. id: menuArea
  64. anchors.fill: parent
  65. onClicked: root.menuClicked()
  66. }
  67. }
  68. // конец реализации кнопки меню
  69. }
  70. }

main.qml

А тут буде вміщено код того, заради чого і писався цей урок. Показати, як реалізувати саме меню.

  1. import QtQuick 2.10
  2. import QtQuick.Window 2.10
  3. import QtQuick.Controls 2.3
  4. import QtQuick.Controls.Material 2.1
  5.  
  6. ApplicationWindow {
  7. id: root
  8. visible: true
  9. width: 360
  10. height: 520
  11. title: qsTr("QML Menu")
  12.  
  13. // Добавляем ActionBar в окно приложения
  14. header: ActionBar {
  15. onMenuClicked: actionBarMenu.open() // Открываем меню
  16.  
  17. // Добавляем меню
  18. Menu {
  19. id: actionBarMenu
  20. // С указанием расположения, чтобы Menu выскакивало в том же месте,
  21. // что и в варианте с Java
  22. x: root.width
  23. y: 48
  24. Menu {
  25. title: qsTr("Information")
  26. Action {
  27. text: qsTr("First")
  28. // Обработка клика по меню
  29. onTriggered: label.text = qsTr("First Info Item is pressed")
  30. }
  31. Action {
  32. text: qsTr("Second")
  33. onTriggered: label.text = qsTr("Second Info Item is pressed")
  34. }
  35. }
  36. Action {
  37. text: qsTr("About")
  38. onTriggered: label.text = qsTr("About Menu Item is pressed")
  39. }
  40. }
  41. }
  42.  
  43. Label {
  44. id: label
  45. anchors.centerIn: parent
  46. text: qsTr("Hello World!")
  47. font.pixelSize: 14
  48. }
  49. }

Висновок

Звичайно, є деяка різниця в реалізації меню за замовчуванням для Java і Qt QML, наприклад наявність заголовка підменю. Теоретично в QML це можна реалізувати за допомогою порожнього Action, який матиме title, буде трохи кастомізований і нічого не робитиме при кліку, але чи потрібно це?

Вам це подобається? Поділіться в соціальних мережах!

Михаиллл
  • 09 липня 2019 р. 19:33
  • (відредаговано)

Добрый день.
Как в такое меню добавить картинку и просто лэйблы с текстом?
И скажите пожалуйста как связаны ActionBar.qml и main.qml?

Михаиллл
  • 10 липня 2019 р. 14:08
  • (відредаговано)

Превый файл скопировал, в другой qml вставил этот код, но меню не появляется

  1. ActionBar {
  2. onMenuClicked: actionBarMenu.open() // Открываем меню
  3.  
  4. // Добавляем меню
  5. Menu {
  6. id: actionBarMenu
  7. // С указанием расположения, чтобы Menu выскакивало в том же месте,
  8. // что и в варианте с Java
  9. x: root.width
  10. y: 48
  11. Menu {
  12. title: qsTr("Information")
  13. Action {
  14. text: qsTr("First")
  15. // Обработка клика по меню
  16. //onTriggered: label.text = qsTr("First Info Item is pressed")
  17. }
  18. Action {
  19. text: qsTr("Second")
  20. //onTriggered: label.text = qsTr("Second Info Item is pressed")
  21. }
  22. }
  23. Action {
  24. text: qsTr("About")
  25. //onTriggered: label.text = qsTr("About Menu Item is pressed")
  26. }
  27. }
  28. }

Вот так работает

  1. Button {
  2.  
  3. x: 5
  4. y: 5
  5. id: menuButton
  6. text: "Menu"
  7. onClicked: myMenu.open()
  8.  
  9. }
  10.  
  11. Menu {
  12. id: myMenu
  13. x: 5
  14. y: menuButton.height
  15.  
  16. MenuItem {
  17. text: "Мои данные"
  18. onClicked: console.log("Мои данные")
  19. }
  20. MenuItem {
  21. text: "Чат"
  22. onClicked: console.log("Чат")
  23. }
  24. MenuItem {
  25. text: "Видео"
  26. onClicked: console.log("Видео")
  27. }
  28. MenuItem {
  29. text: "Контакты"
  30. onClicked: console.log("Контакты")
  31. }
  32.  
  33. }
Evgenii Legotckoi
  • 11 липня 2019 р. 14:27
  • (відредаговано)

У объектов MenuItem есть свойства iconName и iconSource. В iconSource можно добавить иконку из ресурсов в проекте. Можете воспользоваться этим свойством и тогда у вас будут в пунктах меню и иконки и текст.

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
  • Останні коментарі
  • Evgenii Legotckoi
    16 квітня 2025 р. 17:08
    Благодарю за отзыв. И вам желаю всяческих успехов!
  • IscanderChe
    12 квітня 2025 р. 17:12
    Добрый день. Спасибо Вам за этот проект и отдельно за ответы на форуме, которые мне очень помогли в некоммерческих пет-проектах. Профессиональным программистом я так и не стал, но узнал мно…
  • AK
    01 квітня 2025 р. 11:41
    Добрый день. В данный момент работаю над проектом, где необходимо выводить звук из программы в определенное аудиоустройство (колонки, наушники, виртуальный кабель и т.д). Пишу на Qt5.12.12 поско…
  • Evgenii Legotckoi
    09 березня 2025 р. 21:02
    К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
  • VP
    09 березня 2025 р. 16:14
    Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…