C# wpf 实现底部嵌入HwndHost

news2024/10/8 18:17:20

WPF Hwnd窗口互操作系列

第一章 嵌入Hwnd窗口
第二章 嵌入WinForm控件
第三章 嵌入WPF控件
第四章 底部嵌入HwndHost(本章)


文章目录

  • WPF Hwnd窗口互操作系列
  • 前言
  • 一、如何实现?
    • 1、底部创建窗口
      • (1)、创建透明窗口
      • (2)、监控顶部窗口事件
      • (3)、窗口保持在底部
    • 2、HwndHost加入底部窗口
    • 3、Clip穿透顶部窗口
    • 4、WPF控件放在装饰层
  • 二、完整代码
    • 1、对象定义
    • 2、完整代码
  • 三、使用示例
    • 1、嵌入Winform控件
    • 2、显示视频
    • 3、圆角矩形视频
    • 4、拖动位置大小
  • 总结


前言

前面三章内容是笔者基于本章内容研发过程中的附带产物,但是意外的发现第三章可嵌入wpf控件后,本章的意义就变得不那么大了。本章讲述如何从底部嵌入hwnd窗口,以此来做到嵌入窗口不覆盖wpf控件的效果,这种实现思路参考了flutter的一个插件flutter_native_view,其内部实现就用了这种方式。对于wpf实现会复杂一些,因为提供自绘没有BlendMode之类的东西,无法直接消除底部画面,能够使用的方式是Clip,这种方式限制比较多。不过最终还是实现了功能。


一、如何实现?

1、底部创建窗口

(1)、创建透明窗口

 _backgroundWindow = new Window() { WindowStyle = WindowStyle.None, ResizeMode = ResizeMode.NoResize, Focusable = false, Width = 0, Height = 0, ShowInTaskbar = false, ShowActivated = false, Background = Brushes.Transparent, Content = new Grid(), AllowsTransparency = true, };
 _backgroundHandle = (new WindowInteropHelper(_backgroundWindow)).EnsureHandle();

(2)、监控顶部窗口事件

添加hook监控上层窗口的事件

HwndSource.FromHwnd(_forgroundHandle).AddHook(new HwndSourceHook(WndProc));

(3)、窗口保持在底部

监控相关事件保证窗口始终贴在下面。

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    switch (msg)
    {
        case WM_ACTIVATE:
        case WM_MOVE:
        case WM_SIZE:
            RECT rect;
            GetWindowRect(_forgroundHandle, out rect);
            SetWindowPos(_backgroundHandle, _forgroundHandle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE);
            break;
    }
    return IntPtr.Zero;
}

2、HwndHost加入底部窗口

需要嵌入的hwnd窗口,直接嵌入到底部窗口。下列代码中Content是HwndHost控件,在xaml中设置。在cs代码中直接将其添加到底部窗口中。

[ContentProperty("Content")]
public class HwndHostBottomEmbbeder : FrameworkElement
{
    public HwndHost Content
    {
        get { return (HwndHost)GetValue(HostProperty); }
        set { SetValue(HostProperty, value); }
    }
}
var grid = _backgroundWindow.Content as Grid;
grid.Children.Add(Content);

3、Clip穿透顶部窗口

和其他嵌入方式一样,需要先继承HwndHost。clip原理参考《C# wpf利用Clip属性实现截屏框》

//顶部窗口句柄
IntPtr _forgroundHandle = IntPtr.Zero;
//底部窗口句柄
IntPtr _backgroundHandle = IntPtr.Zero;
//底部窗口句柄
Window _backgroundWindow = null;
//顶部窗口
Window _foregroundWindow = null;
//顶部窗口的Content
FrameworkElement? _foreroundContent;
//嵌入窗口的区域
RectangleGeometry? _clipRect;
private void NativeHost_LayoutUpdated(object? sender, EventArgs e)
{
    if (_foreroundContent == null) _foreroundContent = _foregroundWindow.Content as FrameworkElement;
    //计算控件在底部窗口的位置
    var pos = TranslatePoint(new Point(0, 0), _foregroundWindow);
    var dp = pos - Content.TranslatePoint(new Point(0, 0), _backgroundWindow);
    Content.Margin = new Thickness(Content.Margin.Left + dp.X, Content.Margin.Top + dp.Y, Content.Margin.Right - dp.X, Content.Margin.Bottom - dp.Y);
    Content.SetSize(ActualWidth, ActualHeight);
    //创建clip
    var gg = _foreroundContent.Clip as GeometryGroup;
    if (gg == null)
    {
        _foreroundContent.Clip = gg = new GeometryGroup();
        gg.FillRule = FillRule.EvenOdd;
        var rg = new RectangleGeometry();
        rg.Rect = new Rect(0, 0, _foreroundContent.ActualWidth, _foreroundContent.ActualHeight);
        gg.Children.Add(rg);
        gg.Children.Add(new CombinedGeometry() { Geometry1 = new RectangleGeometry(), Geometry2 = new GeometryGroup() { FillRule = FillRule.Nonzero } });
    }
    //底下的rect必须保持和容器大小一致
    var backRg = gg.Children.First() as RectangleGeometry;
    //上层形状即为穿透区域,CombinedGeometry类型用于支持任意个区域穿透
    var foreRg = (gg.Children[1] as CombinedGeometry).Geometry2 as GeometryGroup;
    if (_clipRect == null)
    {
        _clipRect = new RectangleGeometry();
        //添加当前控件的穿透区域
        foreRg.Children.Add(_clipRect);
    }
    var newRect = new Rect(0, 0, _foreroundContent.ActualWidth, _foreroundContent.ActualHeight);
    //判断窗口大小是否改变
    if (backRg.Rect != newRect)
    {
        backRg.Rect = newRect;
    }
    pos = TranslatePoint(new Point(0, 0), _foreroundContent);
    newRect = new Rect(pos.X, pos.Y, ActualWidth, ActualHeight);
    //判断控件区域是否变化
    if (_clipRect.Rect != newRect)
    {
        _clipRect.Rect = newRect;
    }
}

4、WPF控件放在装饰层

由于clip会截其范围内的所有控件,所有有clip的控件上面放置其他控件是看不到的,但是clip不会截取装饰层的控件,所有我们可将控件放到装饰层。
添加一个装饰器属性,在xaml中使用

public class HwndHostBottomEmbbeder : FrameworkElement
 {
     public UIElement Adorner
     {
         get { return (UIElement)GetValue(ContentProperty); }
         set { SetValue(ContentProperty, value); }
     }
}  

定义一个装饰器对象

class NormalAdorner : Adorner
{
    UIElement _child;
    /// <summary>
    /// 构造方法
    /// </summary>
    /// <param name="adornedElement">被添加装饰器的元素</param>
    /// <param name="child">放到装饰器中的元素</param>
    public NormalAdorner(UIElement adornedElement, UIElement child) : base(adornedElement)
    {
        _child = child;
        AddVisualChild(child);
    }
    public UIElement Child => _child;
    protected override Visual GetVisualChild(int index) => _child;
    protected override int VisualChildrenCount => 1;
    protected override System.Windows.Size ArrangeOverride(Size finalSize)
    {
        _child.Arrange(new Rect(new Point(0, 0), finalSize));
        return finalSize;
    }
}

在初始化代码中将xaml中设置的Adorner属性的控件加入到装饰层。要注意添加一个容器用于获取鼠标事件,将事件透传到原本的控件(clip后无法响应鼠标事件)。

var layer = AdornerLayer.GetAdornerLayer(c);
if (layer == null)
    throw new Exception("获取控件装饰层失败,控件可能没有装饰层!");                       
var grid = new Grid();
grid.Background = Brushes.Transparent;
grid.DataContext = c;
grid.SetBinding(Grid.VisibilityProperty, new Binding("Visibility") { Mode = BindingMode.OneWay });
//事件透传
c.MouseByPassFrom(grid);
if (adronerContent != null)
{
    grid.Children.Add(adronerContent);
}
layer.Add(new NormalAdorner((UIElement)c, grid));

二、完整代码

1、对象定义

 /************************************************************************
   * @Project:  	HwndHostBottomEmbbeder
   * @Decription:  底部Hwnd嵌入器,是一个控件,可包含HwndHost控件将其变成底部嵌入,wpf控件显示在装饰层上。
   *               当前版本使用限制:
   *               1、窗口需要设置WindowChrome,
   *               2、会占用Window.Content的Clip属性,
   *               3、不能点击穿透到Hwnd窗口。
   *               4、不支持半透明或全透明背景色窗口,因为嵌入hwnd窗口拖动会有残影。
   *               当前版本适用于显示视频之类的不需要交互的hwnd控件。
   * @Verision:  	v1.0.0
   * @Author:  	Xin Nie
   * @Create:  	2024/03/29 17:33:00
   * @LastUpdate:  2024/03/29 17:33:00
   ************************************************************************
   * Copyright @ 2024. All rights reserved.
   ************************************************************************/
[ContentProperty("Content")]
public class HwndHostBottomEmbbeder : FrameworkElement
{
    /// <summary>
    /// HwndHost控件
    /// </summary>
    public HwndHost Content { get; set; }
    /// <summary>
    /// 装饰层控件
    /// </summary>
    public UIElement Adorner { get; set; }
}

2、完整代码

之后上传


三、使用示例

1、嵌入Winform控件

MainWindow.xaml

<Window x:Class="WpfHwndElement.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfHwndElement"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Background="Transparent"
        WindowStyle="None"   
        ResizeMode="NoResize"
        Title="MainWindow" Height="360" Width="640"       
        xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"  
        >
    <WindowChrome.WindowChrome>
        <WindowChrome GlassFrameThickness="-1"   CaptionHeight="0"   />
    </WindowChrome.WindowChrome >
    <Grid  Margin="0" Background="#ffffffff"  >
        <local:HwndHostBottomEmbbeder   Height="200" Width="200" >
            <!--将WindowsFormsHost转换到底部-->
            <WindowsFormsHost>
                <wf:TextBox  Text="WinForm Text Box"    BackColor="255,	77,78,141" />
            </WindowsFormsHost>
            <!--在装饰层放wpf控件-->
            <local:HwndHostBottomEmbbeder.Adorner>
                <ToggleButton Margin="5"  Width="25" Height="30" Cursor="Hand"  >
                    <ToggleButton.Template>
                        <ControlTemplate TargetType="ToggleButton">
                            <Grid Background="Transparent">
                                <Polygon x:Name="pol" Points="0,0 25,15 0,30" Fill="Gray" Visibility="Visible"></Polygon>
                                <Rectangle  x:Name="rec1" HorizontalAlignment="Left" Width="8" Fill="Gray" Visibility="Hidden"></Rectangle>
                                <Rectangle  x:Name="rec2" HorizontalAlignment="Right"   Width="8" Fill="Gray" Visibility="Hidden"></Rectangle>
                            </Grid>
                        </ControlTemplate>
                    </ToggleButton.Template>
                </ToggleButton>
            </local:HwndHostBottomEmbbeder.Adorner>
        </local:HwndHostBottomEmbbeder>
    </Grid>
</Window>

效果预览
在这里插入图片描述

2、显示视频

示例代码依赖了《播放器》
MainWindow.xaml

<Window x:Class="WpfHwndElement.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfHwndElement"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Background="Transparent"
        WindowStyle="None"   
        ResizeMode="NoResize"
        Title="MainWindow" Height="360" Width="640"    
        xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"  
        >
    <WindowChrome.WindowChrome>
        <WindowChrome GlassFrameThickness="-1"   CaptionHeight="0"   />
    </WindowChrome.WindowChrome >
    <Grid  Margin="0" Background="#ffffffff"  >
        <local:HwndHostBottomEmbbeder   Height="200" Width="200" >
            <!--将WindowsFormsHost转换到底部-->
            <WindowsFormsHost>
                <wf:TextBox  x:Name="tb_video" Text="WinForm Text Box"    BackColor="255,77,78,141" />
            </WindowsFormsHost>
            <!--在装饰层放wpf控件-->
            <local:HwndHostBottomEmbbeder.Adorner>
                <Border Width="150" Height="150" >
                    <ToggleButton Margin="5"  Width="25" Height="30" Cursor="Hand"   Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked">
                        <ToggleButton.Template>
                            <ControlTemplate TargetType="ToggleButton">
                                <Grid Background="Transparent">
                                    <Polygon x:Name="pol" Points="0,0 25,15 0,30" Fill="Gray" Visibility="Visible"></Polygon>
                                    <Rectangle  x:Name="rec1" HorizontalAlignment="Left" Width="8" Fill="Gray" Visibility="Hidden"></Rectangle>
                                    <Rectangle  x:Name="rec2" HorizontalAlignment="Right"   Width="8" Fill="Gray" Visibility="Hidden"></Rectangle>
                                </Grid>
                                <ControlTemplate.Triggers>
                                    <Trigger Property="IsChecked" Value="True">
                                        <Setter TargetName="pol" Property="Visibility" Value="Hidden"></Setter>
                                        <Setter TargetName="rec1" Property="Visibility" Value="Visible"></Setter>
                                        <Setter TargetName="rec2" Property="Visibility" Value="Visible"></Setter>
                                    </Trigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </ToggleButton.Template>
                    </ToggleButton>
                </Border>
            </local:HwndHostBottomEmbbeder.Adorner>
        </local:HwndHostBottomEmbbeder>
    </Grid>
</Window>

MainWindow.xaml.cs

using AC;
using System.Windows;

namespace WpfHwndElement
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Play _play;
        public MainWindow()
        {
            InitializeComponent();
        }
   
        private void ToggleButton_Checked(object sender, RoutedEventArgs e)
        {
            if (_play == null)
            {
                _play = new Play();
                _play.IsLoop = true;
                //获取tb_video的句柄,通过句柄渲染
                _play.Window = tb_video.Handle;
                _play.HardwareAccelerateType = HardwareAccelerateType.Dxva2;
                //开始播放,播放器会在传入的句柄窗口中渲染视频。
                _play.Start(@"D:\测试\Sony_4K_Camp_Main.mp4");      
            }
            else
            {
         
                _play.IsPause = false;
            }
      
        }
        private void ToggleButton_Unchecked(object sender, RoutedEventArgs e)
        {
            _play.IsPause = true;
        }
   }
}

效果预览
效

3、圆角矩形视频

示例代码依赖了《播放器》
MainWindow.xaml

<Window x:Class="WpfHwndElement.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfHwndElement"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Background="Transparent"
        WindowStyle="None"   
        ResizeMode="NoResize"
        Title="MainWindow" Height="360" Width="640"   
        ac:Resize.IsResizeable="True"
        ac:Resize.IsWindowDragSmooth="True"
        ac:Move.IsDragMoveable="True"      
        xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"  
        >
    <WindowChrome.WindowChrome>
        <WindowChrome GlassFrameThickness="-1"   CaptionHeight="0"   />
    </WindowChrome.WindowChrome >
    <Grid  Margin="0" Background="#ffffffff"  >
        <local:HwndHostBottomEmbbeder   Height="200" Width="200"   >
            <!--裁剪圆角矩形-->
            <local:HwndHostBottomEmbbeder.Clip>
                <RectangleGeometry Rect="0 0 200 200" RadiusX="10" RadiusY="10"></RectangleGeometry>
            </local:HwndHostBottomEmbbeder.Clip>
            <!--将WindowsFormsHost转换到底部-->
            <WindowsFormsHost>
                <wf:TextBox  x:Name="tb_video" Text="WinForm Text Box"  BorderStyle="None"  BackColor="255,77,78,141" />
            </WindowsFormsHost>
            <!--在装饰层放wpf控件-->
            <local:HwndHostBottomEmbbeder.Adorner>
                <Border Width="150" Height="150" >
                    <ToggleButton Margin="5"  Width="25" Height="30" Cursor="Hand"   Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked">
                        <ToggleButton.Template>
                            <ControlTemplate TargetType="ToggleButton">
                                <Grid Background="Transparent">
                                    <Polygon x:Name="pol" Points="0,0 25,15 0,30" Fill="Gray" Visibility="Visible"></Polygon>
                                    <Rectangle  x:Name="rec1" HorizontalAlignment="Left" Width="8" Fill="Gray" Visibility="Hidden"></Rectangle>
                                    <Rectangle  x:Name="rec2" HorizontalAlignment="Right"   Width="8" Fill="Gray" Visibility="Hidden"></Rectangle>
                                </Grid>
                                <ControlTemplate.Triggers>
                                    <Trigger Property="IsChecked" Value="True">
                                        <Setter TargetName="pol" Property="Visibility" Value="Hidden"></Setter>
                                        <Setter TargetName="rec1" Property="Visibility" Value="Visible"></Setter>
                                        <Setter TargetName="rec2" Property="Visibility" Value="Visible"></Setter>
                                    </Trigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </ToggleButton.Template>
                    </ToggleButton>
                </Border>
            </local:HwndHostBottomEmbbeder.Adorner>
        </local:HwndHostBottomEmbbeder>
    </Grid>
</Window>

MainWindow.xaml.cs
cs代码同上略。
效果预览
在这里插入图片描述

4、拖动位置大小

示例代码依赖了《拖动》和《调整大小》还有《播放器》
MainWindow.xaml

<Window x:Class="WpfHwndElement.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfHwndElement"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Background="Transparent"
        WindowStyle="None"   
        ResizeMode="NoResize"
        Title="MainWindow" Height="360" Width="640"   
        ac:Resize.IsResizeable="True"
        ac:Move.IsDragMoveable="True"      
        xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"  
        >
    <WindowChrome.WindowChrome>
        <WindowChrome GlassFrameThickness="-1"   CaptionHeight="0"   />
    </WindowChrome.WindowChrome >
    <Grid  Margin="0" Background="#ffffffff"  >
        <local:HwndHostBottomEmbbeder   Height="200" Width="200"  ac:Resize.IsResizeable="True"  ac:Move.IsDragMoveable="True" >
            <!--将WindowsFormsHost转换到底部-->
            <WindowsFormsHost>
                <!--使用窗体设置全透明-->
                <wf:Form  x:Name="tb_video"  TopLevel="False" FormBorderStyle="None"  />
            </WindowsFormsHost>
            <!--在装饰层放wpf控件-->
            <local:HwndHostBottomEmbbeder.Adorner>
                <!--非播放时wpf层填充颜色,避免直接透到桌面-->
                <Border x:Name="bd_mask"  Background="RoyalBlue">
                    <ToggleButton Margin="5"  Width="25" Height="30" Cursor="Hand"   Checked="ToggleButton_Checked" Unchecked="ToggleButton_Unchecked">
                        <ToggleButton.Template>
                            <ControlTemplate TargetType="ToggleButton">
                                <Grid Background="Transparent">
                                    <Polygon x:Name="pol" Points="0,0 25,15 0,30" Fill="Gray" Visibility="Visible"></Polygon>
                                    <Rectangle  x:Name="rec1" HorizontalAlignment="Left" Width="8" Fill="Gray" Visibility="Hidden"></Rectangle>
                                    <Rectangle  x:Name="rec2" HorizontalAlignment="Right"   Width="8" Fill="Gray" Visibility="Hidden"></Rectangle>
                                </Grid>
                                <ControlTemplate.Triggers>
                                    <Trigger Property="IsChecked" Value="True">
                                        <Setter TargetName="pol" Property="Visibility" Value="Hidden"></Setter>
                                        <Setter TargetName="rec1" Property="Visibility" Value="Visible"></Setter>
                                        <Setter TargetName="rec2" Property="Visibility" Value="Visible"></Setter>
                                    </Trigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </ToggleButton.Template>
                    </ToggleButton>
                </Border>
            </local:HwndHostBottomEmbbeder.Adorner>
        </local:HwndHostBottomEmbbeder>
    </Grid>
</Window>

MainWindow.xaml.cs

using AC;
using System.Reflection;
using System.Windows;

namespace WpfHwndElement
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Play _play;
        public MainWindow()
        {

            InitializeComponent();                 
        }

        private void ToggleButton_Checked(object sender, RoutedEventArgs e)
        {
            if (_play == null)
            {

                _play = new Play();
                _play.IsLoop = true;
                //获取tb_video的句柄,通过句柄渲染
                _play.Window = tb_video.Handle;
                _play.HardwareAccelerateType = HardwareAccelerateType.Dxva2;
                //开始播放,播放器会在传入的句柄窗口中渲染视频。
                _play.Start(@"D:\Sony_4K_Camp.mp4");
                //实现透明窗口,避免拖动时与视频绘制冲突,出现界面闪烁
                tb_video.GetType().GetMethod("SetStyle", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(tb_video, new object[] { ControlStyles.Opaque, true });
            }
            else
            {
         
                _play.IsPause = false;
            }
            bd_mask.Background =System.Windows.Media. Brushes.Transparent;

        }
        private void ToggleButton_Unchecked(object sender, RoutedEventArgs e)
        {
            _play.IsPause = true;
            bd_mask.Background = System.Windows.Media.Brushes.RoyalBlue;
        }
  }
}

在这里插入图片描述


总结

以上就是今天要讲的内容,本章的实现是有一定难度的,其灵感来源有flutter,也是刚好发现wpf的Clip属性能做到穿透,才有了实现本章的基础,但是限制也不小,当然作为初步探索的版本,以后可以继续优化。本章实现的嵌入方式虽然有限制,但还是能够用来做视频渲染的,尤其是需要做圆角边框以及拖动的场景,就能做到渲染性能和界面效果的完美结合。

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

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

相关文章

[flink 实时流基础]源算子和转换算子

文章目录 1. 源算子 Source1. 从集合读2. 从文件读取3. 从 socket 读取4. 从 kafka 读取5. 从数据生成器读取数据 2. 转换算子基本转换算子&#xff08;map/ filter/ flatMap&#xff09; 1. 源算子 Source Flink可以从各种来源获取数据&#xff0c;然后构建DataStream进行转换…

ios应用内支付

用uniapp开发iOS应用内支付 准备前端代码服务器端处理如果iOS支付遇到问题实在解决不了&#xff0c;可以联系我帮忙解决&#xff0c;前端后端都可以解决&#xff08;添加的时候一定要备注咨询iOS支付问题&#xff09; 准备前端代码 获取支付通道 (uni.getProvider) uni.getPr…

怎么更新sd-webui AUTOMATIC1111/stable-diffusion-webui ?

整个工程依靠脚本起来的&#xff1a; 可直接到stable-diffusion-webui子目录执行&#xff1a; git pull更新代码完毕后&#xff0c;删除venv的虚拟环境。 然后再次执行webui.sh&#xff0c;这样会自动重新启动stable-diffusion-webui.

Netty核心原理剖析与RPC实践21-25

Netty核心原理剖析与RPC实践21-25 21 技巧篇&#xff1a;延迟任务处理神器之时间轮 HahedWheelTimer Netty 中有很多场景依赖定时任务实现&#xff0c;比较典型的有客户端连接的超时控制、通信双方连接的心跳检测等场景。在学习 Netty Reactor 线程模型时&#xff0c;我们知道…

卸载原有的cuda,更新cuda

概述&#xff1a;看了一下自己的gpu&#xff0c;发现驱动可能装低了&#xff0c;随即尝试更新驱动&#xff0c;写下此篇 注&#xff1a;我原先是10.2的版本&#xff0c;改了之后是11.2&#xff0c;下面的图都用11.2的&#xff0c;不过不碍事 目录 第一步&#xff1a;查看现在…

SmartChart的部署以及可能遇见的报错解决方案

简介 数据可视化是一种将数据转化为图形的技术&#xff0c;可以帮助人们更好地理解和分析数据。但是&#xff0c;传统的数据可视化开发往往需要编写大量的代码&#xff0c;或者使用复杂的拖拽工具&#xff0c;不仅耗时耗力&#xff0c;而且难以实现个性化的需求。有没有一种更…

深度解析:Elasticsearch检索请求原理

在上一篇文章中&#xff0c;我们学习了 Elasticsearch 的写入流程&#xff0c;今天我们来学习一下 Elasticsearch 的读取流程&#xff0c;当一个检索请求到达 Elasticsearch 之后是如何进行检索的呢&#xff1f; 下面先说一下一个总的检索流程。 1、客户端发送请求到任意一个…

深度思考:雪花算法snowflake分布式id生成原理详解

雪花算法snowflake是一种优秀的分布式ID生成方案&#xff0c;其优点突出&#xff1a;它能生成全局唯一且递增的ID&#xff0c;确保了数据的一致性和准确性&#xff1b;同时&#xff0c;该算法灵活性强&#xff0c;可自定义各部分bit位&#xff0c;满足不同业务场景的需求&#…

13-API风格(下):RPCAPI介绍

RPC在Go项目开发中用得也非常多&#xff0c;需要我们认真掌握。 RPC介绍 根据维基百科的定义&#xff0c;RPC&#xff08;Remote Procedure Call&#xff09;&#xff0c;即远程过程调用&#xff0c;是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机…

【面经八股】搜广推方向:面试记录(十一)

【面经&八股】搜广推方向:面试记录(十一) 文章目录 【面经&八股】搜广推方向:面试记录(十一)1. 自我介绍2. 实习经历问答4. 编程题5. 反问1. 自我介绍 。。。。。。 2. 实习经历问答 就是对自己实习事情要足够的清晰,不熟的不要写在简历上!!! 其中,有个 …

电脑分辨率怎么调,电脑分辨率怎么调整

随着电脑的普及以及网络的发展&#xff0c;我们现在在工作中都离不开对电脑的使用&#xff0c;今天小编教大家设置电脑分辨率&#xff0c;现在我们先了解这个分辨率是什么?通常电脑的显示分辨率就是屏幕分辨率&#xff0c;显示屏大小固定时&#xff0c;显示分辨率越高图像越清…

【Node.js】WebSockets

概述 WebSockets是一种在浏览器和服务器之间建立持久连接的协议&#xff0c;它允许服务器主动推送数据给客户端&#xff0c;并且在客户端和服务器之间实现双向通信。 建立连接&#xff1a;客户端通过在JavaScript代码中使用WebSocket对象来建立WebSockets连接。例如&#xff1…

KUKA机器人KR FORTEC-2 ultra重型机器人介绍

额定负载在480-800kg的KR FORTEC-2 ultra重型机器人专为快速精确处理高惯量的大型部件的工艺而设计&#xff0c;双支撑连接臂使性能更强&#xff0c;并可以在紧凑的空间内保持优异性能。在工业生产中&#xff0c;工件的转动惯量越大&#xff0c;对机器人的有效载荷和臂展要求越…

安全SCDN的威胁情报库对DDOS防护有什么好处

目前网络攻击事件频频发生&#xff0c;DDoS&#xff08;分布式拒绝服务&#xff09;攻击已成为各种企业&#xff08;小到区域性小公司大到各种跨国公司&#xff09;的主要威胁&#xff0c;DDoS 攻击可能会对企业造成重大损害和破坏&#xff0c;比如对目标公司的业务造成产生不利…

探索父进程和子进程

文章目录 通过系统调用查看进程PID父进程、子进程 通过系统调用创建进程-fork初识为什么fork给父进程返回子进程的PID&#xff0c;给子进程返回0fork函数如何做到返回两个值一个变量为什么同时会有两个返回值&#xff1f;bash总结 通过系统调用查看进程PID getpid()函数可以获…

win10配置CLion2022+ubuntu20.04远程部署

背景 在博文ubunut搭建aarch64 cuda交叉编译环境记录中&#xff0c;使用的ubuntu20.04虚拟机安装eclipse来交叉编译aarch64的程序&#xff0c;然后发送到jetson板子上执行。开发一段时间后发现eclipse IDE使用起来不太便捷&#xff0c;因此&#xff0c;考虑使用CLion IDE&…

接口自动化框架搭建(四):pytest的使用

1&#xff0c;使用说明 网上资料比较多&#xff0c;我这边就简单写下 1&#xff0c;目录结构 2&#xff0c;test_1.py创建两条测试用例 def test_1():print(test1)def test_2():print(test2)3&#xff0c;在pycharm中执行 4&#xff0c;执行结果&#xff1a; 2&#xff0…

新能源汽车充电桩常见类型及充电桩站场的智能监管方案

随着新能源汽车市场的迅猛发展&#xff0c;充电桩作为支持其运行的基础设施&#xff0c;也呈现出多样化的类型。这些充电桩不仅在外形和功能上存在差异&#xff0c;更在充电速度、充电方式以及使用场景等方面展现出独特的优势。 一、充电桩类型及区别 1、慢充桩&#xff08;交…

《算法笔记》系列----质数的判断(埃氏筛法)

目录 一、朴素算法 二、埃氏筛法 1、与朴素算法对比 2、算法介绍 3、例题即代码实现 一、朴素算法 从素数的定义中可以知道&#xff0c;一个整数n要被判断为素数&#xff0c;需要判断n是否能被2.3.n- 1中的一个整除。只2&#xff0c;3..n- 1都不能整除n&#xff0c;n才能…

Coursera自然语言处理专项课程03:Natural Language Processing with Sequence Models笔记 Week02

Natural Language Processing with Sequence Models Course Certificate 本文是https://www.coursera.org/learn/sequence-models-in-nlp 这门课程的学习笔记&#xff0c;如有侵权&#xff0c;请联系删除。 文章目录 Natural Language Processing with Sequence ModelsWeek 02…