c# Avalonia 架构开发跨平台应用

news2024/11/15 10:45:17

 实现了一个计算器的应用,先看在不同平台的效果

windows11上

ubuntu上

统信UOS 上

麒麟 kylin v10 

 好了,先说一下问题,如果想一套代码在不同平台同时运行,里面调用的逻辑还是要分系统的,先分linux系统和windows系统,macOS等,然后不同系统里面还要再细分,如linux下的ubuntu,kylin,uos等,这里主要说一下在linux系统上,经常出错的一个问题就是下面的:

 Could not create glyphTypeface. 

Unhandled exception. System.InvalidOperationException: Could not create glyphTypeface. Font family: $Default (key: ). Style: Normal. Weight: Normal. Stretch: Normal
   at Avalonia.Media.Typeface.get_GlyphTypeface()
   at Avalonia.Rendering.Composition.Compositor.get_DiagnosticTextRenderer()
   at Avalonia.Rendering.Composition.Compositor.CreateCompositionTarget(Func`1 surfaces)
   at Avalonia.Rendering.Composition.CompositingRenderer..ctor(IRenderRoot root, Compositor compositor, Func`1 surfaces)
   at Avalonia.Controls.TopLevel..ctor(ITopLevelImpl impl, IAvaloniaDependencyResolver dependencyResolver)
   at Avalonia.Controls.WindowBase..ctor(IWindowBaseImpl impl, IAvaloniaDependencyResolver dependencyResolver)
   at Avalonia.Controls.WindowBase..ctor(IWindowBaseImpl impl)
   at Avalonia.Controls.Window..ctor(IWindowImpl impl)
   at Avalonia.Controls.Window..ctor()
   at GetStartedApp.MainWindow..ctor() in D:\working\c#_test\GetStartedApp\MainWindow.axaml.cs:line 10
   at GetStartedApp.App.OnFrameworkInitializationCompleted() in D:\working\c#_test\GetStartedApp\App.axaml.cs:line 18
   at Avalonia.AppBuilder.SetupUnsafe()
   at Avalonia.AppBuilder.Setup()
   at Avalonia.AppBuilder.SetupWithLifetime(IApplicationLifetime lifetime)
   at Avalonia.ClassicDesktopStyleApplicationLifetimeExtensions.StartWithClassicDesktopLifetime(AppBuilder builder, String[] args, Action`1 lifetimeBuilder)
   at GetStartedApp.Program.Main(String[] args) in D:\working\c#_test\GetStartedApp\Program.cs:line 12
已放弃 (核心已转储)

主要原因是加载的字体不存在就报bug了。刚上也有自己安装字体的解决方法,参见

http://t.csdnimg.cn/4otvKicon-default.png?t=N7T8http://t.csdnimg.cn/4otvK但是上文没有我试过这么多系统

最好的方法是在每个系统中使用已经自带的字体。改代码Program.cs如下

using Avalonia;
using Avalonia.Media; 
using System;
using System.Drawing.Text;
using System.Linq;
using System.Runtime.InteropServices;

namespace CalculatorApp;

class Program
{
    [STAThread]
    public static void Main(string[] args) => BuildAvaloniaApp()
                .StartWithClassicDesktopLifetime(args);

    // BuildAvaloniaApp 是应用程序的启动方法,负责配置并启动 Avalonia 应用程序。
    public static AppBuilder BuildAvaloniaApp()
    {
        // 初始化默认的字体名称为空字符串
        string defaultFont = "";

        // 检查当前操作系统是否是 Linux 系统
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
        {
            // 获取当前操作系统的描述信息,通常包含操作系统的名称和版本
            string osDescription = RuntimeInformation.OSDescription.ToLower();
            Console.WriteLine("osDescription: " + osDescription);

            // 检查操作系统描述是否包含 "uniontech",如果是,表示是 UOS 系统
            if (osDescription.Contains("uniontech"))
            {
                // 设置默认字体为 "Noto Sans"(这是 UOS 系统中常见的字体)
                defaultFont = "Noto Sans";
            }
            // 检查操作系统描述是否包含 "kylin",如果是,表示是麒麟 v10 系统
            else if (osDescription.Contains("kylin"))
            {
                // 设置默认字体为 "Arial"(麒麟系统中常用的字体)
                defaultFont = "Arial";
            }
            // 检查操作系统描述是否包含 "ubuntu",如果是,表示是 Ubuntu 系统
            else if (osDescription.Contains("ubuntu"))
            {
                // 设置默认字体为 "Noto Mono"(Ubuntu 中常用的等宽字体)
                defaultFont = "Noto Mono";
            }
        }

        // 创建 FontManagerOptions 对象,并设置默认的字体名称
        FontManagerOptions options = new FontManagerOptions
        {
            DefaultFamilyName = defaultFont // 通过操作系统检测结果设置的默认字体
        };

        // 输出当前使用的字体信息到控制台,以便调试和验证
        Console.WriteLine("Using font: " + options.DefaultFamilyName);

        // 返回一个 AppBuilder 实例,配置并启动 Avalonia 应用程序
        return AppBuilder.Configure<App>()      // 配置应用程序
            .UsePlatformDetect()                // 自动检测运行平台(Windows, Linux, macOS)
            .WithInterFont()                    // 配置默认字体为 InterFont,作为默认字体集
            .LogToTrace()                       // 允许日志信息输出到控制台,方便调试
            .With(options);                     // 应用字体选项
    }
}

只有上面这个代码配好了,后面的逻辑在各个linux平台上才没有问题。

下面写出界面代码  ,文件名 MainWindow.axaml,其后缀为axaml与wpf中常用的xaml多个a表示使用的是Avalonia架构。这个代码定义了一个简洁的计算器界面,使用 Avalonia 框架构建。通过数据绑定和命令模式,实现了将界面操作与业务逻辑分离的设计。

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="CalculatorApp.MainWindow"
        Title="手搓计算器"
        Width="350" Height="650"
        MinWidth="300" MinHeight="580"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:CalculatorApp"
        mc:Ignorable="d"
        x:DataType="local:MainWindowViewModel"
        Background="#F0F0F0"
        WindowStartupLocation="CenterScreen"
		KeyDown="Window_KeyDown">
	<!-- 设置窗体居中 -->

	<!-- 主布局容器 -->
	<Grid Margin="10">
		<Grid.RowDefinitions>
			<RowDefinition Height="100"/>
			<!-- 设置显示屏的行高度 -->
			<RowDefinition Height="40"/>
			<!-- 设置结果显示行的高度 -->
			<RowDefinition Height="100"/>
			<!-- 预留的一行(可以放其他功能) -->
			<RowDefinition Height="*"/>
			<!-- 按钮行,占用剩余空间 -->
		</Grid.RowDefinitions>

		<!-- 显示屏,显示输入的数字和操作 -->
		<Grid Grid.Row="0">
			<!-- 显示输入的数字,右对齐,字体大小为 40 -->
			<Label Name="DisplayAll" FontSize="40" Content="{Binding DisplayAll}" HorizontalContentAlignment="Right" VerticalContentAlignment="Center"/>
		</Grid>

		<!-- 显示当前计算结果 -->
		<Grid Grid.Row="1">
			<!-- 显示计算结果,右对齐,字体大小为 30 -->
			<Label Name="DisplayResult" FontSize="30" Content="{Binding DisplayResult}" HorizontalContentAlignment="Right" VerticalContentAlignment="Center"/>
		</Grid>

		<!-- 按钮区域,设置按钮布局 -->
		<Grid Grid.Row="3">
			<!-- 定义按钮的行 -->
			<Grid.RowDefinitions>
				<RowDefinition Height="1*"/>
				<!-- 每行高度相等,使用比例分配 -->
				<RowDefinition Height="1*"/>
				<RowDefinition Height="1*"/>
				<RowDefinition Height="1*"/>
				<RowDefinition Height="1*"/>
			</Grid.RowDefinitions>

			<!-- 定义按钮的列 -->
			<Grid.ColumnDefinitions>
				<ColumnDefinition Width="1*"/>
				<!-- 每列宽度相等,使用比例分配 -->
				<ColumnDefinition Width="1*"/>
				<ColumnDefinition Width="1*"/>
				<ColumnDefinition Width="1*"/>
			</Grid.ColumnDefinitions>

			<!-- 第一行按钮 -->
			<Button Content="C" Grid.Row="0" Grid.Column="0" Classes="clear" Command="{Binding ClearCommand}"/>
			<!-- 清除按钮,绑定清除命令 -->
			<!-- 暂时未添加的功能按钮 -->
			<!-- <Button Content="±" Grid.Row="0" Grid.Column="1" Command="{Binding NegateCommand}"/>-->
			<!--<Button Content="%" Grid.Row="0" Grid.Column="2" Command="{Binding PercentCommand}"/>-->
			<Button Content="÷" Grid.Row="0" Grid.Column="3" Classes="operator" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="/"/>
			<!-- 除法按钮,绑定操作命令 -->

			<!-- 第二行按钮 -->
			<Button Content="7" Grid.Row="1" Grid.Column="0" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="7"/>
			<!-- 数字 7 -->
			<Button Content="8" Grid.Row="1" Grid.Column="1" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="8"/>
			<!-- 数字 8 -->
			<Button Content="9" Grid.Row="1" Grid.Column="2" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="9"/>
			<!-- 数字 9 -->
			<Button Content="×" Grid.Row="1" Grid.Column="3" Classes="operator" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="*"/>
			<!-- 乘法按钮 -->

			<!-- 第三行按钮 -->
			<Button Content="4" Grid.Row="2" Grid.Column="0" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="4"/>
			<!-- 数字 4 -->
			<Button Content="5" Grid.Row="2" Grid.Column="1" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="5"/>
			<!-- 数字 5 -->
			<Button Content="6" Grid.Row="2" Grid.Column="2" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="6"/>
			<!-- 数字 6 -->
			<Button Content="−" Grid.Row="2" Grid.Column="3" Classes="operator" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="-"/>
			<!-- 减法按钮 -->

			<!-- 第四行按钮 -->
			<Button Content="1" Grid.Row="3" Grid.Column="0" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="1"/>
			<!-- 数字 1 -->
			<Button Content="2" Grid.Row="3" Grid.Column="1" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="2"/>
			<!-- 数字 2 -->
			<Button Content="3" Grid.Row="3" Grid.Column="2" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="3"/>
			<!-- 数字 3 -->
			<Button Content="+" Grid.Row="3" Grid.Column="3" Classes="operator" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="+"/>
			<!-- 加法按钮 -->

			<!-- 第五行按钮 -->
			<Button Content="0" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="0" HorizontalAlignment="Stretch"/>
			<!-- 数字 0,占两列 -->
			<Button Content="." Grid.Row="4" Grid.Column="2" Command="{Binding AddDigitOrOperationCommand}" CommandParameter="."/>
			<!-- 小数点按钮 -->
			<Button Content="=" Grid.Row="4" Grid.Column="3" Classes="equals" Command="{Binding EqualsCommand}"/>
			<!-- 等于按钮,绑定等于命令 -->
		</Grid>
	</Grid>
</Window>

MainWindow.axaml.cs的代码

这个代码在 Avalonia UI 框架下,实现了按键输入处理功能。通过判断用户按下的键来触发计算器的相应操作,例如输入数字、执行加减乘除等操作,并通过 ViewModel 中的命令绑定来更新界面和执行计算逻辑。

using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Remote.Protocol.Input;
using System;
using Key = Avalonia.Input.Key;  // 为避免与其他命名空间中的 Key 冲突,显式定义 Key

namespace CalculatorApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();  // 初始化组件(加载 XAML UI)
            DataContext = new MainWindowViewModel();  // 设置数据上下文为 MainWindowViewModel,进行数据绑定
        }

        // 处理按键事件的方法,当用户按下键盘时触发
        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            // 获取当前的 ViewModel
            var viewModel = DataContext as MainWindowViewModel;

            // 如果 ViewModel 为空,则直接返回,不进行任何操作
            if (viewModel == null)
                return;

            // 根据按下的键执行相应的操作

            // 检查是否按下了数字键 0-9,并且没有按下 Shift 键
            if (e.Key >= Key.D0 && e.Key <= Key.D9 && e.KeyModifiers.HasFlag(KeyModifiers.Shift) == false)
            {
                // 将数字转换为字符串并传递给命令
                string digit = (e.Key - Key.D0).ToString();
                viewModel.AddDigitOrOperationCommand.Execute(digit);
            }
            // 检查是否按下了加号键(+),支持数字键盘的加号以及 Shift + OemPlus(通常是 + 键)
            else if (e.Key == Key.Add || (e.Key == Key.OemPlus && e.KeyModifiers.HasFlag(KeyModifiers.Shift)))
            {
                viewModel.AddDigitOrOperationCommand.Execute("+");
            }
            // 检查是否按下了减号键(-)
            else if (e.Key == Key.Subtract)
            {
                viewModel.AddDigitOrOperationCommand.Execute("-");
            }
            // 检查是否按下了乘号键(*),支持数字键盘的乘号以及 Shift + 8(通常是 * 键)
            else if (e.Key == Key.Multiply || (e.Key == Key.D8 && e.KeyModifiers.HasFlag(KeyModifiers.Shift)))
            {
                viewModel.AddDigitOrOperationCommand.Execute("*");
            }
            // 检查是否按下了除号键(/),支持数字键盘的除号以及 Oem2(通常是 / 键)
            else if (e.Key == Key.Divide || e.Key == Key.Oem2)
            {
                viewModel.AddDigitOrOperationCommand.Execute("/");
            }
            // 检查是否按下了等于号键(=)或回车键(Enter)
            else if (e.Key == Key.OemPlus || e.Key == Key.Enter)
            {
                viewModel.AddDigitOrOperationCommand.Execute("=");
            }
            // 检查是否按下了删除键(Backspace)或删除键(Delete)
            else if (e.Key == Key.Back || e.Key == Key.Delete)
            {
                viewModel.ClearCommand.Execute(null);  // 执行清除命令
            }
        }
    }
}

 MainWindow.axaml.cs代码

using Avalonia.Input;
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;

namespace CalculatorApp
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        // 私有字段,用于存储显示的文本、当前操作符、结果和其他操作状态
        private string _displayText = "0";  // 显示屏的默认值为 "0"
        private string _displaySymbol = "";  // 用于显示当前的运算符号
        private string _displayResult = "";  // 显示最终的运算结果
        private string _currentOperation;  // 当前正在进行的操作符
        private double _firstNumber;  // 存储第一个操作数
        private bool _isOperationPending;  // 标志是否有未完成的操作
        private bool _isNewEntry = true;  // 标志是否是新的输入
        private bool _isResultDisplayed = false;  // 标志是否刚刚显示了计算结果
        private string _displayAll;  // 用于显示所有操作记录

        // 实现 INotifyPropertyChanged 接口,用于通知 UI 属性的变化
        public event PropertyChangedEventHandler PropertyChanged;

        public MainWindowViewModel()
        {
            // 初始化命令,将按钮绑定到相应的命令
            AddDigitOrOperationCommand = new RelayCommand<string>(AddDigitOrOperation);  // 处理数字和操作符的输入
            ClearCommand = new RelayCommand(Clear);  // 处理清除操作
            EqualsCommand = new RelayCommand(Calculate);  // 处理等于操作
        }

        // 公有属性,用于绑定 UI
        public string DisplayAll
        {
            get => _displayAll;
            set
            {
                _displayAll = value;
                OnPropertyChanged(nameof(DisplayAll));  // 通知 UI 属性已更改
            }
        }

        public string DisplayText
        {
            get => _displayText;
            set
            {
                _displayText = value;
                OnPropertyChanged();  // 使用 CallerMemberName 自动获取属性名称
            }
        }

        public string DisplaySymbol
        {
            get => _displaySymbol;
            set
            {
                _displaySymbol = value;
                OnPropertyChanged();
            }
        }

        public string DisplayResult
        {
            get => _displayResult;
            set
            {
                _displayResult = value;
                OnPropertyChanged();
            }
        }

        // 命令用于处理各种用户操作
        public ICommand AddDigitOrOperationCommand { get; }  // 处理数字或操作符
        public ICommand ClearCommand { get; }  // 清除输入和结果
        public ICommand EqualsCommand { get; }  // 执行等于运算
        public ICommand NegateCommand { get; }  // 处理取反操作(可扩展)
        public ICommand PercentCommand { get; }  // 处理百分比操作(可扩展)

        // 根据输入值判断是数字还是操作符
        private void AddDigitOrOperation(string input)
        {
            if (IsOperation(input))
            {
                SetOperation(input);  // 如果是操作符,则调用 SetOperation
            }
            else
            {
                AddDigit(input);  // 如果是数字,则调用 AddDigit
            }
        }

        // 判断输入是否是操作符
        private bool IsOperation(string input)
        {
            return input == "+" || input == "-" || input == "*" || input == "/" || input == "=";
        }

        // 添加数字到显示屏
        private void AddDigit(string digit)
        {
            // 如果刚刚显示过结果,清空显示
            if (_isResultDisplayed)
            {
                DisplayAll = "";
                DisplayResult = "";
                _isResultDisplayed = false;
            }

            // 如果是新输入,则替换显示内容,否则追加
            if (_isNewEntry)
            {
                DisplayText = digit == "." ? "0." : digit;
                _isNewEntry = false;
                DisplayAll += digit;
            }
            else
            {
                // 避免重复输入小数点
                if (digit == "." && DisplayText.Contains("."))
                    return;

                DisplayText += digit;
                DisplayAll += digit;
            }
        }

        // 设置操作符并处理运算
        private void SetOperation(string operation)
        {
            if (!_isOperationPending)  // 如果当前没有进行中的操作
            {
                _firstNumber = double.Parse(DisplayText);  // 解析输入的第一个数字
                _currentOperation = operation;  // 保存当前操作符
                _isOperationPending = true;  // 标记操作进行中
                _isNewEntry = true;  // 准备接受新的输入

                // 显示操作符
                switch (operation)
                {
                    case "+":
                    case "-":
                    case "*":
                    case "/":
                        DisplaySymbol = operation;
                        break;
                    case "=":
                        Calculate();  // 如果操作符是 "=", 则执行计算
                        return;
                }
                DisplayAll += DisplaySymbol;
            }
            else
            {
                // 如果有进行中的操作,执行计算后再设置新的操作符
                Calculate();
                _currentOperation = operation;
            }
        }

        // 执行计算逻辑
        private void Calculate()
        {
            if (!_isOperationPending)
                return;

            double secondNumber = double.Parse(DisplayText);  // 获取输入的第二个数字
            double result = 0;

            try
            {
                // 根据操作符计算结果
                switch (_currentOperation)
                {
                    case "+":
                        result = _firstNumber + secondNumber;
                        break;
                    case "-":
                        result = _firstNumber - secondNumber;
                        break;
                    case "*":
                        result = _firstNumber * secondNumber;
                        break;
                    case "/":
                        if (secondNumber == 0)
                            throw new DivideByZeroException();
                        result = _firstNumber / secondNumber;
                        break;
                }

                // 更新显示结果
                DisplayAll += "=";
                DisplayResult = result.ToString();
                _firstNumber = result;  // 将结果作为下一次操作的第一个数字
                _isNewEntry = true;
                _isOperationPending = false;
                _isResultDisplayed = true;  // 标记刚刚显示了结果
            }
            catch (Exception)
            {
                DisplayText = "Error";  // 捕获错误,例如除零错误
                _isNewEntry = true;
                _isOperationPending = false;
                DisplaySymbol = "";
            }
        }

        // 清除输入和结果
        private void Clear()
        {
            DisplayText = "0";  // 重置显示屏
            DisplaySymbol = "";  // 清除操作符
            DisplayAll = "";  // 清空所有显示
            DisplayResult = "";  // 清空结果
            _firstNumber = 0;  // 重置第一个数字
            _currentOperation = null;  // 清除当前操作符
            _isOperationPending = false;  // 重置操作状态
            _isNewEntry = true;  // 重置为新输入状态
            _isResultDisplayed = false;  // 重置结果显示状态
        }

        // 通知属性已更改,刷新 UI
        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }

    // RelayCommand 类:用于绑定命令和操作
    public class RelayCommand<T> : ICommand
    {
        private readonly Action<T> _execute;  // 执行操作的委托
        private readonly Func<T, bool> _canExecute;  // 判断操作是否可以执行的委托

        public RelayCommand(Action<T> execute, Func<T, bool> canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        // 判断命令是否可以执行
        public bool CanExecute(object parameter) => _canExecute == null || _canExecute((T)parameter);

        // 执行命令
        public void Execute(object parameter) => _execute((T)parameter);

        // 事件,当命令的可执行状态发生变化时触发
        public event EventHandler CanExecuteChanged
        {
            add { }
            remove { }
        }
    }

    // 不带参数的 RelayCommand 类,用于绑定简单操作
    public class RelayCommand : ICommand
    {
        private readonly Action _execute;
        private readonly Func<bool> _canExecute;

        public RelayCommand(Action execute, Func<bool> canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        // 判断命令是否可以执行
        public bool CanExecute(object parameter) => _canExecute == null || _canExecute();

        // 执行命令
        public void Execute(object parameter) => _execute();

        // 事件,当命令的可执行状态发生变化时触发
        public event EventHandler CanExecuteChanged
        {
            add { }
            remove { }
        }
    }
}

另外就是发布成各种平台的方法了:

右击工程点击发布-》选择文件夹,相当于支持了win,linux,osx,以及x86,x64,arm多种架构。

下载代码如下:

AvaloniaCalculatorApp: 一个基于Avalonia架构的c#简单的计算器应用,支持windows ,linux(ubuntu,kylin,uos),visual 2022开发 (gitee.com)icon-default.png?t=N7T8https://gitee.com/sunyuzhe114/AvaloniaCalculatorApp

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2106006.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024年全国铁路(铁路、高铁、地铁)矢量数据集

数据更新时间​&#xff1a;2024年6月​&#xff1b; ​数据范围&#xff1a;全国各省&#xff08;不包含台湾&#xff09;; 数据格式​&#xff1a;shp; ​数据包含类型&#xff1a;铁路、高铁、地铁 数据​坐标信息&#xff1a; EPSG Code 4326 大地基准面 D_WGS_1…

CTFSHOWRCE

web3 1.打开环境&#xff0c;上面给了一句php的话&#xff0c;意思是get传参url有文件包含漏洞 2.get传参运用伪协议&#xff0c;post传参命令执行看目录。 3.上面有一个文件ctf_go_go_go,访问这个文件就有flag web4 1.打开环境&#xff0c;和上一关的一样&#xff0c;但是不…

CSS实现优惠券透明圆形镂空打孔效果等能力学习

前言&#xff1a;无他&#xff0c;仅供学习记录&#xff0c;通过一个简单的优惠券Demo实践巩固CSS知识。 本次案例主要学习或巩固一下几点&#xff1a; 实现一个简单的Modal&#xff1b;如何进行复制文本到粘贴板&#xff1b;在不使用UI的svg图片的情况下&#xff0c;如何用C…

【C++】模板特化

目录 一、非类型模板参数 二、模板的特化 &#x1f31f;概念 扩展小知识补充(1)&#xff1a; 扩展小知识补充(2)&#xff1a; &#x1f31f;函数模板特化 扩展小知识&#xff1a; &#x1f31f;类模板特化 ✨全特化 ✨偏特化 • 部分特化&#xff1a;将模板参数表中…

前端几种常见框架【第一节】

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; 最近比较忙&#xff0c;本人在复习软考中级设计考试&#xff0c;所以本系列文从零基础开始复习软考到结束软考&#xff08;计算机技术与软件专业技术资格考试&#xff09;作为国家级职业资格认证考试&#x…

ROS2 2D相机基于AprilTag实现3D空间定位最简流程

文章目录 前言驱动安装下载安装方式一&#xff1a;方式二&#xff1a; 相机检测配置config文件编译、运行程序注意 内参标定标定板运行程序 apriltag空间定位标签打印下载安装可视化结果 前言 AprilTag是一种高性能的视觉标记系统&#xff0c;广泛应用于机器人导航、增强现实和…

简述CCS平面线性光源

光源在机器视觉系统中起着重要作用&#xff0c;不同环境、场景及应用合适光源都不一样&#xff0c;今天我们来看看LFX3-PT系列平面线性光源。它是最适合检测镜面物体的凹凸,外壳小巧的光源。备有根据检测条件可选的2种线间距。1mm型&#xff08;型号末尾&#xff1a;A&#xff…

【ArcGIS Pro第一期】界面简介

ArcGIS Pro简介 ArcGIS Pro界面简介1.1 打开工程1.2 使用功能区上的工具 参考 ArcGIS Pro 是一种基于功能区的应用程序。 ArcGIS Pro 窗口顶部的功能区有许多命令可供选择&#xff0c;而根据需要打开的各个窗格&#xff08;可停靠窗口&#xff09;中则提供了更为高级或专用的功…

erlang学习:用ETS和DETS存储数据

作用 ets和dets是两个系统模块&#xff0c;可以用来高效存储海量的Erlang数据。 ETS和DETS执行的任务基本相同&#xff1a;它们提供大型的键值查询表。ETS常驻内存&#xff0c;DETS则常驻磁盘。ETS是相当高效的&#xff1a;可以用它存储海量的数据&#xff08;只要有足够的内…

ACM模式 输入输出练习

牛客-练习地址 第一题 let cnt readline(); while(cnt--){let input readline()let arr input.split( ).map(Number)console.log(arr[0]arr[1]) }第二题 let cnt readline(); while(cnt--){let input readline()let arr input.split( ).map(Number)console.log(arr[0]ar…

Web攻防之应急响应(二)

目录 前提 &#x1f354;学习Java内存马前置知识 内存马 内存马的介绍 内存马的类型众多 内存马的存在形式 Java web的基础知识&#xff1a; Java内存马的排查思路&#xff1a; &#x1f354;开始查杀之前的需要准备 1.登录主机启动服务器 2.生成jsp马并连接成功 …

vivado 创建时间约束1

步骤3&#xff1a;创建时间约束 在此步骤中&#xff0c;您打开合成的设计并使用AMD Vivado™定时约束 男巫定时约束向导分析门级网表并发现缺失 约束。使用“定时约束”向导为此设计生成约束。 1.在“流导航器”中&#xff0c;单击“打开综合设计”。 2.当综合设计打开时&#…

六、MySQL高级—架构介绍(1)

&#x1f33b;&#x1f33b; 目录 一、Mysql 简介1.1 概述1.2 Mysql 高手是怎样炼成的 二、Mysql Linux 版的安装2.1 mysql5.52.2 mysql5.7 三、Mysql 的用户与权限管理3.1 MySQL的用户管理3.2 权限管理3.3 通过工具远程访问 四、 Mysql的一些杂项配置(了解)五、 Mysql 逻辑架构…

[UVM]3.核心基类 uvm_object 域的自动化 copy() compare() print() pack unpack

1.核心基类&#xff1a;uvm_object &#xff08;1&#xff09;虚类只能声明&#xff0c;不能例化。 &#xff08;2&#xff09;uvm_object提供的方法 2.域的自动化&#xff08;field automation&#xff09; &#xff08;1&#xff09;简述 &#xff08;2&#xff09;示例 格…

JVM5-垃圾回收

自动垃圾回收 在C/C这类没有自动垃圾回收机制的语言中&#xff0c;一个对象如果不再使用&#xff0c;需要手动释放&#xff0c;否则就会出现内存泄漏&#xff0c;称这种释放对象的过程为垃圾回收&#xff0c;而需要程序员编写代码进行回收的方式为手动回收 内存泄漏指的是不再…

进一步了解CSS布局——WEB开发系列29

CSS 页面布局技术允许我们拾取网页中的元素&#xff0c;并且控制它们相对正常布局流、周边元素、父容器或者主视口/窗口的位置。 一、正常布局流&#xff08;Normal Flow&#xff09; CSS的布局基础是“正常流”&#xff0c;也就是页面元素在没有特别指定布局方式时的默认排列…

OPenCV结构分析与形状描述符(3)计算一个点集的最小外接矩形的函数boundingRect()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 计算一个点集的最小右上边界矩形或灰度图像中的非零像素。 该函数计算并返回指定点集或灰度图像中非零像素的最小右上边界矩形。 在OpenCV中&am…

[项目][CMP][项目介绍及知识铺垫]详细讲解

目录 1.这个项目做的是什么&#xff1f;2.此项目涉及知识面3.什么是内存池&#xff1f;1.池化技术2.内存池3.内存池主要解决的问题 4.理解malloc 1.这个项目做的是什么&#xff1f; 实现一个高并发内存池&#xff0c;参考原型为Google的一个开源项目tcmalloc(Thread-Caching M…

61、Python之函数高级:为函数添加方法,实现属性可变的装饰器

引言 今天文章的标题&#xff0c;初读起来可能有些拗口&#xff0c;什么叫“为函数添加方法”&#xff1f;但是&#xff0c;如果真正对“Python函数也是对象”这个理念有清晰的理解的话&#xff0c;其实&#xff0c;也是不难理解的&#xff0c;本质上就是给一个对象新增一个自…

通用代码生成器还可以这么用,将MariaDB数据库连数据迁徙到PostgreSQL

通用代码生成器是一种非常方便的软件开发工具&#xff0c;除了简单直接的生成代码&#xff0c;制作快速原型以外。通用代码生成器还可以应用在各种场景上。比如可以使用通用代码生成器&#xff0c;将MariaDB数据库连数据迁徙到PostgreSQL。操作并不复杂&#xff0c;却十分适用。…