前言
在使用WinUI 3/Windows App SDK(C++/WinRT)进行开发时,难免会遇到想到需要在后台自动修改窗口UI内容的需求,本文将介绍一种通过线程修改UI内容的方法。文章的前半部分主要介绍开发工具以及项目的初始化,如果你已熟悉这部分内容,可直接阅读文章的最后一部分。
安装Visual Studio及相关开发包
在Visual Studio官网下载Visual Studio Community 2022
下载完成后,打开Visual Studio Installer,勾选桌面应用和移动应用下的使用C++的桌面开发以及通用Windows平台开发。此外,针对使用C++的桌面开发,还需要在右侧的安装详细信息中勾选Windows 应用 SDK C++ 模板,后续我们将基于此模板进行开发。
创建模板应用
打开Visual Studio 2022,点击Create a new project,然后依次筛选C++,Windows,WinUI,在筛选结果中选择Blank App, Packaged (WinUI 3 in Desktop)后点击Next, 输入项目名并选择项目存放路径后,点击Create创建项目。
创建完成后,点击工具栏的Local Machine进行本地调试,如跳出以下窗口,则表示项目创建成功。
修改模板应用
现在我们已经创建了一个简单的WinUI 3模板应用,它只有一个按钮置于窗口中央,点击此按钮后,按钮中的文字将从Click Me变成Clicked。在本项目中,我们并不需要这个按钮,而是需要一个TextBlock来显示数字,并通过线程让数字每隔1秒加一。
首先,我们删除这个按钮。打开MainWindow.xaml,删除Button标签。
<Button x:Name="myButton" Click="myButton_Click">Click Me</Button>
同时,我们还需要将此按钮关联的事件方法也一并删除。打开MainWindow.xaml.h,在头文件中删除该方法的定义。
void myButton_Click(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args);
打开MainWindow.xaml.cpp,将其实现也删除。
void MainWindow::myButton_Click(IInspectable const&, RoutedEventArgs const&)
{
myButton().Content(box_value(L"Clicked"));
}
接着,我们在MainWindow.xaml中,添加一个名为txt的TextBlock。
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock x:Name="txt" HorizontalAlignment="Center" />
</StackPanel>
打开MainWindow.xaml.cpp,在MainWindow的构造函数中,我们可以在MainWindow被创建时,通过调用txt对象(txt即为上面添加的TextBlock)的Text()方法,给TextBlock的文本内容赋值。需要注意的是,在C++/WinRT中,字符串多为hstring,因此需要将普通的字符数组或者字符串转化成hstring,可以通过调用to_hstring()或者在字符串前面加一个L来实现。
MainWindow::MainWindow()
{
InitializeComponent();
txt().Text(to_hstring(100)); // 或者txt().Text(L"100");
}
再次点击Local Machine进行本地调试,你将看到窗口中央出现显示着100。
通过线程修改UI内容
首先,在MainWindow.xaml.h中定义一个线程成员,一个bool类型的变量(用来终止循环),一个int类型的变量(不断变化的数字),线程的运行方法,以及一个解构函数(在MainWindow销毁时回收线程)。
namespace winrt::WinUI_3_Thread_UI_Change::implementation
{
struct MainWindow : MainWindowT<MainWindow>
{
std::thread UI_change_thread;
bool thread_finished;
int count;
MainWindow();
~MainWindow();
void UI_change_thread_function();
int32_t MyProperty();
void MyProperty(int32_t value);
};
}
接着打开MainWindow.xaml.cpp,我们先实现下线程的运行方法UI_change_thread_function()。如果你先前接触过使用Dispatcher().RunAsync来实现线程修改UI,那么我强烈建议你阅读下微软官网文档中Threading functionality migration的部分内容,因为在Windows App SDK中,微软对线程相关的一部分方法进行了迁移,如果继续使用老的方法,会遇到非常多的问题。在Windows App SDK中,我们主要使用DispatcherQueue的TryEnqueue()来让线程进入到队列中等待执行,或者HasThreadAccess判断当前线程是否被DispatcherQueue选中,如果选中则直接运行相关操作。此外,我们通过使用sleep_for()来让线程休眠特定的时间,其参数为std::chrono::milliseconds()。
void MainWindow::UI_change_thread_function() {
while (thread_finished) {
if (this->DispatcherQueue().HasThreadAccess())
{
txt().Text(to_hstring(count++));
}
else
{
this->DispatcherQueue().TryEnqueue(
Microsoft::UI::Dispatching::DispatcherQueuePriority::Normal,
[this]()
{
txt().Text(to_hstring(count++));
});
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
有了线程运行方法后,我们便可以在MainWindow的构造函数中,实例化一个线程并赋值给我们先前定义的线程成员UI_change_thread,以方便我们在解构函数中回收它。同时,在这里也对count和thread_finished做了初始化操作。
MainWindow::MainWindow()
{
InitializeComponent();
count = 0;
thread_finished = true;
UI_change_thread = std::thread(&MainWindow::UI_change_thread_function, this);
}
最后在解构函数~MainWindow中,我们先将thread_finished设置为false,以让线程中的循环终止。这样UI_change_thread便可以完成运行并成为joinable的状态,我们只要对它调用join()便可以回收了。
MainWindow::~MainWindow() {
thread_finished = false;
if (UI_change_thread.joinable()) {
UI_change_thread.join();
}
}
再次点击Local Machine进行本地调试,就可以看到窗口中央的数字每隔1秒加一。
今天的文章修改线程名称_WindowsGUI程序编写分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/82454.html