QT界面样式转鸿蒙APP开发记录

268 阅读2分钟

image.png

一、样式1

✅ 项目结构说明(基于 ArkTS)

entry/
 ├── src/
 │    └── main/
 │         ├── ets/
 │         │     ├── MainAbility/
 │         │     │     ├── MainAbility.ets
 │         │     │     └── pages/
 │         │     │          └── DeviceConfigPage.ets   ← 主页面界面逻辑
 │         └── resources/
 │               └── base/
 │                    ├── media/
 │                    │    └── back.jpg                ← 背景图
 │                    └── layout/
 │                         └── main_pages.json         ← 页面注册

📄 DeviceConfigPage.ets

import { CommonConstants } from '../utils/CommonConstants';

@Entry
@Component
struct DeviceConfigPage {
  @State width: number = 320
  @State height: number = 240
  @State selectedPort: string = ''
  @State selectedBaud: string = '115200'
  @State selectedType: string = 'RGB565'

  portList: Array<string> = ['COM1', 'COM2', 'COM3']
  baudRateList: Array<string> = ['921600', '1382400', '460800', '115200', '9600']
  imageTypes: Array<string> = ['RGB565']

  build() {
    Column({ space: 20 }) {
      // 串口选择
      this.buildComboRow('串口', this.portList, this.selectedPort, val => this.selectedPort = val)

      // 波特率选择
      this.buildComboRow('波特率', this.baudRateList, this.selectedBaud, val => this.selectedBaud = val)

      // 图像宽
      this.buildSpinRow('图像宽', this.width, val => this.width = val)

      // 图像高
      this.buildSpinRow('图像高', this.height, val => this.height = val)

      // 图像类型
      this.buildComboRow('图像类型', this.imageTypes, this.selectedType, val => this.selectedType = val)
    }
    .width('100%')
    .padding(20)
    .backgroundImage($r('media/back.jpg'), ImageRepeat.NoRepeat)
  }

  buildComboRow(labelText: string, items: Array<string>, selected: string, onChange: (v: string) => void) {
    Row({ space: 10 }) {
      Text(`${labelText}:`)
        .fontSize(18)
        .width(100)
        .textAlign(TextAlign.Start)

      Select({
        value: selected,
        options: items,
        onSelect: onChange
      })
      .fontSize(18)
      .width(150)
    }
  }

  buildSpinRow(labelText: string, value: number, onChange: (v: number) => void) {
    Row({ space: 10 }) {
      Text(`${labelText}:`)
        .fontSize(18)
        .width(100)
        .textAlign(TextAlign.Start)

      TextInput({
        text: value.toString(),
        onChange: (v: string) => {
          const num = parseInt(v)
          if (!isNaN(num) && num >= 10 && num <= 2000) {
            onChange(num)
          }
        }
      })
      .width(150)
      .fontSize(18)
      .type(InputType.Number)
    }
  }
}

📄 MainAbility.ets

import DeviceConfigPage from './pages/DeviceConfigPage'

@Entry
@Component
struct MainAbility {
  build() {
    Navigator() {
      Scene({
        id: 'config',
        component: DeviceConfigPage
      })
    }
  }
}

📄 resources/base/media/back.jpg

请将你 Qt 项目中使用的 back.jpg 背景图放入这个文件夹。


🔧 页面注册 (仅用于旧版 HarmonyOS,如果用 ArkTS 模板默认支持)

// main_pages.json
{
  "pages": [
    {
      "name": "DeviceConfigPage",
      "component": "entry/src/main/ets/pages/DeviceConfigPage.ets"
    }
  ]
}

二、样式2

下面是使用 Java + XMLDevEco Studio (HarmonyOS Java 开发模式) 下,实现 Qt UI 中“设备配置”界面。


✅ 效果要求:

参考 Qt 的 .ui 文件,这个界面包含:

  • 背景图片
  • 串口下拉框(ComboBox)
  • 波特率下拉框
  • 图像宽度、高度输入框(SpinBox)
  • 图像类型下拉框

🧱 项目结构

entry/
 └── src/main/
      ├── java/你的包名/
      │    └── MainAbilitySlice.java
      ├── resources/
      │    ├── base/
      │    │    ├── layout/
      │    │    │    └── ability_main.xml   ← UI 界面布局文件
      │    │    ├── media/
      │    │    │    └── back.jpg           ← 背景图
      │    │    └── element/
      │    │         └── strings.xml        ← 字符串资源
      └── config.json

📄 ability_main.xml

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:orientation="vertical"
    ohos:width="match_parent"
    ohos:height="match_parent"
    ohos:alignment="center"
    ohos:background_element="$media:back"
    ohos:padding="16vp">

    <!-- 串口选择 -->
    <Text
        ohos:width="match_parent"
        ohos:height="wrap_content"
        ohos:text="串口:"
        ohos:text_size="18fp" />
    <DependentLayout
        ohos:width="match_parent"
        ohos:height="wrap_content">
        <ComboBox
            ohos:id="$+id:port_combo"
            ohos:width="match_parent"
            ohos:height="40vp" />
    </DependentLayout>

    <!-- 波特率选择 -->
    <Text
        ohos:text="波特率:"
        ohos:width="match_parent"
        ohos:height="wrap_content"
        ohos:text_size="18fp" />
    <ComboBox
        ohos:id="$+id:baud_combo"
        ohos:width="match_parent"
        ohos:height="40vp" />

    <!-- 图像宽度 -->
    <Text
        ohos:text="图像宽:"
        ohos:width="match_parent"
        ohos:height="wrap_content"
        ohos:text_size="18fp" />
    <TextField
        ohos:id="$+id:width_input"
        ohos:width="match_parent"
        ohos:height="40vp"
        ohos:input_type="number"
        ohos:text="320" />

    <!-- 图像高度 -->
    <Text
        ohos:text="图像高:"
        ohos:width="match_parent"
        ohos:height="wrap_content"
        ohos:text_size="18fp" />
    <TextField
        ohos:id="$+id:height_input"
        ohos:width="match_parent"
        ohos:height="40vp"
        ohos:input_type="number"
        ohos:text="240" />

    <!-- 图像类型 -->
    <Text
        ohos:text="图像类型:"
        ohos:width="match_parent"
        ohos:height="wrap_content"
        ohos:text_size="18fp" />
    <ComboBox
        ohos:id="$+id:image_type_combo"
        ohos:width="match_parent"
        ohos:height="40vp" />
</DirectionalLayout>

📄 MainAbilitySlice.java

package com.example.deviceconfig;

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.*;

import java.util.Arrays;
import java.util.List;

public class MainAbilitySlice extends AbilitySlice {
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);

        initUI();
    }

    private void initUI() {
        ComboBox portCombo = (ComboBox) findComponentById(ResourceTable.Id_port_combo);
        ComboBox baudCombo = (ComboBox) findComponentById(ResourceTable.Id_baud_combo);
        ComboBox imageTypeCombo = (ComboBox) findComponentById(ResourceTable.Id_image_type_combo);

        List<String> ports = Arrays.asList("COM1", "COM2", "COM3");
        List<String> baudRates = Arrays.asList("921600", "1382400", "460800", "115200", "9600");
        List<String> imageTypes = Arrays.asList("RGB565");

        portCombo.setData(ports);
        baudCombo.setData(baudRates);
        imageTypeCombo.setData(imageTypes);

        // 默认选择第一项
        portCombo.setSelectedIndex(0);
        baudCombo.setSelectedIndex(3); // 默认115200
        imageTypeCombo.setSelectedIndex(0);
    }
}

📄 strings.xml(可选,用于资源字符串)

<resources>
    <string name="app_name">设备配置</string>
</resources>

📄 背景图片资源

将 Qt 界面使用的背景图命名为 back.jpg,放到如下目录:

entry/src/main/resources/base/media/back.jpg

✅ 编译运行效果

真机或模拟器 中运行时,页面将显示:

  • 背景图;
  • 多行设置项,每行由标签 + 控件组成;
  • 支持选择串口、波特率,输入图像尺寸等;
  • 兼容 HarmonyOS 3.0+ Java 项目开发。

是否还需要添加按钮或功能逻辑(如“保存配置”、“连接设备”)?