亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

WPF用狀態(tài)模式開(kāi)發(fā)截圖功能

 更新時(shí)間:2025年03月18日 09:36:09   作者:caoruipeng  
狀態(tài)模式是設(shè)計(jì)模式中的一種行為設(shè)計(jì)模式,尤其在游戲中開(kāi)發(fā)中還是比較常見(jiàn)的,本文將通過(guò)狀態(tài)模式開(kāi)發(fā)一個(gè)截圖功能,有需要的小伙伴可以參考下

狀態(tài)模式

狀態(tài)模式是設(shè)計(jì)模式中的一種行為設(shè)計(jì)模式,對(duì)很多人來(lái)說(shuō),這個(gè)模式平時(shí)可能用不到。但是如果你做游戲開(kāi)發(fā)的話,我相信你應(yīng)該對(duì)這個(gè)模式有一個(gè)很深刻的理解。狀態(tài)模式在游戲中開(kāi)發(fā)中還是比較常見(jiàn)的。狀態(tài)模式將狀態(tài)的行為封裝在獨(dú)立的狀態(tài)類中,使得狀態(tài)轉(zhuǎn)換變得更加清晰和易于管理。這樣的話,對(duì)象只負(fù)責(zé)狀態(tài)的切換,不負(fù)責(zé)具體的行為。

比如射擊類游戲:玩家模式是原地站立狀態(tài),當(dāng)用戶按下前進(jìn)的時(shí)候,玩家的狀態(tài)切換為前進(jìn)狀態(tài),當(dāng)按下后退的時(shí)候,狀態(tài)切換為后退狀態(tài)。當(dāng)按下鼠標(biāo)左鍵時(shí),玩家進(jìn)入射擊狀態(tài)。對(duì)于同一個(gè)玩家對(duì)象來(lái)說(shuō),不同的狀態(tài)下,都是由不同的行為邏輯。這些邏輯,如果全部都在玩家這個(gè)對(duì)象類中實(shí)現(xiàn)的話,將會(huì)非常復(fù)雜。狀態(tài)模式,就是用來(lái)解決這個(gè)問(wèn)題的。

狀態(tài)模式的主要組成部分包括:

(1)、上下文(Context):維護(hù)一個(gè)具體狀態(tài)的實(shí)例,這個(gè)實(shí)例定義了當(dāng)前的狀態(tài)。

(2)、狀態(tài)接口(State):定義了所有具體狀態(tài)類的公共接口。

(3)、 具體狀態(tài)類(Concrete States):實(shí)現(xiàn)狀態(tài)接口,并根據(jù)上下文的狀態(tài)改變其行為。

下面用C#簡(jiǎn)單的寫一個(gè)狀態(tài)模式的代碼,來(lái)實(shí)現(xiàn)上面的玩家類。

1、定義狀態(tài)接口IPlayerState表示玩家狀態(tài),Handle用于處理不同狀態(tài)下玩家的具體行為

public interface IPlayerState
{
    void Handle(PlayerContext context);
}

2、定義具體狀態(tài)類:默認(rèn)站立狀態(tài)類:DefaultState 、前進(jìn)狀態(tài):MoveForwardState 、后退狀態(tài):MoveBackwardState 、射擊狀態(tài):DesignState 、死亡狀態(tài):DeadState

public class DefaultState : IPlayerState
{
    public void Handle(PlayerContext context)
    {
        Console.WriteLine("玩家處于默認(rèn)站立狀態(tài).");
        // 狀態(tài)轉(zhuǎn)換邏輯
    }
}

public class MoveForwardState : IPlayerState
{
    public void Handle(PlayerContext context)
    {
        Console.WriteLine("玩家正在前進(jìn)....");
        // 狀態(tài)轉(zhuǎn)換邏輯 這里可以實(shí)時(shí)渲染玩家位置
    }
}

public class MoveBackwardState : IPlayerState
{
    public void Handle(PlayerContext context)
    {
        Console.WriteLine("玩家正在后退...");
        // 狀態(tài)轉(zhuǎn)換邏輯 這里可以實(shí)時(shí)渲染玩家位置
    }
}

public class DesignState : IPlayerState
{
    public void Handle(PlayerContext context)
    {
        Console.WriteLine("玩家正在射擊...");
        // 狀態(tài)轉(zhuǎn)換邏輯 這里可以判斷玩家是否擊中對(duì)方,更新對(duì)方血條和自己血條
    }
}

public class DeadState : IPlayerState
{
    public void Handle(PlayerContext context)
    {
        Console.WriteLine("玩家死亡...");
        // 狀態(tài)轉(zhuǎn)換邏輯 這里可以對(duì)本局游戲進(jìn)行玩家分?jǐn)?shù)結(jié)算
    }
}

從上面可以看到,不同的狀態(tài),玩家的邏輯被清晰的描述出來(lái)。這樣的話,我們就不用在玩家類Player中,通過(guò)if-else切換狀態(tài),實(shí)現(xiàn)業(yè)務(wù)邏輯,結(jié)構(gòu)也會(huì)非常清晰。

3、定義上下文類:上下文類中存儲(chǔ)了玩家的當(dāng)前狀態(tài),并且可以通過(guò)上下文切換玩家狀態(tài)。這是狀態(tài)類中最基本的元素,當(dāng)然還可以包含其他的狀態(tài)數(shù)據(jù),比如玩家的實(shí)時(shí)坐標(biāo),玩家的血條信息等等。

public class PlayerContext
{
    private IPlayerState _state;

    public PlayerContext()
    {
        _state = new DefaultState(); // 初始狀態(tài)為默認(rèn)狀態(tài)
    }

    public void SetState(IPlayerState state)
    {
        _state = state;
    }

    public void Request()
    {
        _state.Handle(this);
    }
}

4、在對(duì)象中,切換狀態(tài),調(diào)用對(duì)應(yīng)的狀態(tài)類邏輯。當(dāng)然我們只是在這里手動(dòng)切換狀態(tài) ,實(shí)際開(kāi)發(fā)中,我們一般是監(jiān)聽(tīng)鼠標(biāo)鍵盤事件或者鼠標(biāo)事件之后切換玩家狀態(tài)。

class Program
{
    static void Main(string[] args)
    {
        PlayerContext context = new PlayerContext();

        // 初始狀態(tài)為默認(rèn)狀態(tài)
        context.Request(); 

        // 切換到前進(jìn)狀態(tài)
        context.SetState(new MoveForwardState());
        context.Request(); 

        // 切換到后退狀態(tài)
        context.SetState(new MoveBackwardState());
        context.Request();

        // 切換到設(shè)計(jì)狀態(tài)
        context.SetState(new DesignState());
        context.Request();

        // 切換到死亡狀態(tài)
        context.SetState(new DeadState());
        context.Request(); 
    }
}

基本原理

介紹完?duì)顟B(tài)模式的基本遠(yuǎn)離之后,接下來(lái)介紹截圖功能的基本原理:通過(guò)捕獲屏幕上的特定區(qū)域并將其保存為圖像文件,在WPF中,我們可以使用System.Drawing命名空間中的類來(lái)實(shí)現(xiàn)這一功能。具體步驟如下:

1.    捕獲屏幕區(qū)域:使用Graphics.CopyFromScreen方法從屏幕上復(fù)制指定區(qū)域的像素。

2.    保存圖像:將捕獲的像素?cái)?shù)據(jù)保存為位圖(Bitmap)格式。

3.    顯示或處理圖像:將位圖轉(zhuǎn)換為WPF可以處理的BitmapSource格式,以便在界面上顯示或進(jìn)一步處理。

我們先來(lái)看下如何保存圖像:

public static System.Drawing.Bitmap Snapshot(int x, int y, int width, int height)
{
    System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
    using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap))
    {
        graphics.CopyFromScreen(x, y, 0, 0, new System.Drawing.Size(width, height), System.Drawing.CopyPixelOperation.SourceCopy);
    }
    return bitmap;
}

在截圖過(guò)程中,我們使用了狀態(tài)模式來(lái)管理截圖過(guò)程中的不同狀態(tài)。

當(dāng)我們按下快捷鍵的時(shí)候, 處于默認(rèn)狀態(tài),具體行為是:將一個(gè)WPF窗體背景設(shè)置為透明,寬高設(shè)置為和屏幕大小一致。

當(dāng)我們按下鼠標(biāo)左鍵的時(shí)候,處理開(kāi)始截圖狀態(tài)(鼠標(biāo)左鍵單擊事件),具體行為是:記錄截圖的開(kāi)始坐標(biāo),也就是截圖矩形的左上角坐標(biāo)。

當(dāng)按下鼠標(biāo)開(kāi)始移動(dòng)端時(shí)候,處于截圖中狀態(tài)(鼠標(biāo)移動(dòng)事件),具體行為是:不斷記錄截圖的實(shí)時(shí)坐標(biāo),作為截圖區(qū)域的右下角坐標(biāo),同時(shí)用戶選中的區(qū)域,背景色要設(shè)置成亮色,可以清晰可見(jiàn)。

當(dāng)放開(kāi)鼠標(biāo)的時(shí)候,處于截圖結(jié)束狀態(tài)(鼠標(biāo)左鍵抬起事件),具體行為是:記錄截圖的終止坐標(biāo),也就是截圖舉行的右下角坐標(biāo)。

當(dāng)下鼠標(biāo)移動(dòng)的時(shí)候,處于移動(dòng)中狀態(tài),已經(jīng)選好的截圖區(qū)域是可以移動(dòng)的,具體行為是:記錄鼠標(biāo)移動(dòng) 偏差,動(dòng)態(tài)設(shè)置選中區(qū)域的背景色。

當(dāng)然還有其他的狀態(tài)類,就不一一描述了。

首先定義我們的狀態(tài)類接口IScreentState :表示截圖狀態(tài)類

public interface IScreentState
{
    void ProcessState(StateContext context);
}

其次定義具體的狀態(tài)實(shí)現(xiàn)類:StartState、SelectState、SelectingState、SelectedState、MoveState、MovingState、MovedState、EndState總共有8個(gè)狀態(tài)了,這里我只實(shí)現(xiàn)了截圖和移動(dòng)功能,并沒(méi)有實(shí)現(xiàn)拖拽功能,如果需要拖拽修改截圖區(qū)域大小功能,大家可以自行實(shí)現(xiàn)。

public class StartState : IScreentState
{
    public void ProcessState(StateContext context)
    {
        SnapShotWindow win = context._window;
        win.clipRect.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#8000"));
        win.Cursor = Cursors.Arrow;
        win.leftPanel.Width = 0;
        win.topPanel.Height = 0;
        win.rightPanel.Width = 0;
        win.bottomPanel.Height = 0;
    }
}

public class SelectState : IScreentState
{
    public void ProcessState(StateContext context)
    {
        context._startPoint = context._args.GetPosition(context._window);
    }
}

public class SelectingState : IScreentState
{
    public void ProcessState(StateContext context)
    {
        SnapShotWindow win = context._window;
        win.clipRect.Background = Brushes.Transparent;
        context._endPoint = context._args.GetPosition(win);
        win.leftPanel.Width = context._startPoint.X;
        win.topPanel.Height = context._startPoint.Y;
        win.rightPanel.Width = win.ActualWidth - context._endPoint.X;
        win.bottomPanel.Height = win.ActualHeight - context._endPoint.Y;
        win.snapShotInfo.Text = context.GetText();
    }
}

public class SelectedState : IScreentState
{
    public void ProcessState(StateContext context)
    {
        context._endPoint = context._args.GetPosition(context._window);
    }
}

public class MoveState : IScreentState
{
    public void ProcessState(StateContext context)
    {
        SnapShotWindow win = context._window;
        context._mouseDownPosition = context._args.GetPosition(win);
        context._mouseDownMargin = new Thickness(win.leftPanel.ActualWidth, win.topPanel.ActualHeight, win.rightPanel.ActualWidth, win.bottomPanel.Height); ;

        var relativePosition = context._args.GetPosition(win);
        if (relativePosition.X >= 0 && relativePosition.X <= win.clipRect.ActualWidth &&
            relativePosition.Y >= 0 && relativePosition.Y <= win.clipRect.ActualHeight)
        {
            context._allowMove = true;
            win.Cursor = Cursors.SizeAll;
        }
    }
}

public class MovingState : IScreentState
{
    public void ProcessState(StateContext context)
    {
        SnapShotWindow win = context._window;
        win.Cursor = Cursors.SizeAll;
        //todo 隱藏操作按鈕
        var pos = context._args.GetPosition(win);  //拖拽后鼠標(biāo)的位置
        var dp = pos - context._mouseDownPosition; //鼠標(biāo)移動(dòng)的偏移量
        Thickness newThickness = new Thickness(context._mouseDownMargin.Left + dp.X,
            context._mouseDownMargin.Top + dp.Y,
            context._mouseDownMargin.Right - dp.X,
            context._mouseDownMargin.Bottom - dp.Y);
        win.leftPanel.Width = newThickness.Left < 0 ? 0 : newThickness.Left;
        win.topPanel.Height = newThickness.Top < 0 ? 0 : newThickness.Top;
        win.rightPanel.Width = newThickness.Right < 0 ? 0 : newThickness.Right;
        win.bottomPanel.Height = newThickness.Bottom < 0 ? 0 : newThickness.Bottom;
        win.snapShotInfo.Text = context.GetText();
    }
}

public class MovedState : IScreentState
{
    public void ProcessState(StateContext context)
    {
        //todo 顯示操作按鈕
    }
}

public class EndState : IScreentState
{
    public void ProcessState(StateContext context)
    {
    }
}

最后是狀態(tài)上下文類:

public class StateContext
{
    public IScreentState _currentState;

    public SnapShotWindow _window;
    public MouseEventArgs _args;
    //框選開(kāi)始坐標(biāo)
    public Point _startPoint;
    //框選結(jié)束坐標(biāo)
    public Point _endPoint;
    //目前狀態(tài)
    public ScreenState _state;
    //開(kāi)始拖拽時(shí),鼠標(biāo)按下的位置
    public Point _mouseDownPosition;
    //開(kāi)始拖拽時(shí),鼠標(biāo)按下控件的Margin
    public Thickness _mouseDownMargin;
    public bool _allowMove = false;

    private readonly IScreentState _startState;
    private readonly IScreentState _selectState;
    private readonly IScreentState _selectingState;
    private readonly IScreentState _selectedState;
    private readonly IScreentState _moveState;
    private readonly IScreentState _movingState;
    private readonly IScreentState _movedState;
    private readonly IScreentState _endState;

    public StateContext(SnapShotWindow window)
    {
        _window = window;
        _startState = new StartState();
        _selectState = new SelectState();
        _selectingState = new SelectingState();
        _selectedState = new SelectedState();
        _moveState = new MoveState();
        _movingState = new MovingState();
        _movedState = new MovedState();
        _endState = new EndState();

        _state = ScreenState.Start;
        _currentState = _startState;
        SetNewState(_state);
    }

    public void SetNewState(ScreenState state)
    {
        _state = state;
        switch (state)
        {
            case ScreenState.Start:
                _currentState = _startState;
                break;
            case ScreenState.Select:
                _currentState = _selectState;
                break;
            case ScreenState.Selecting:
                _currentState = _selectingState;
                break;
            case ScreenState.Selected:
                _currentState = _selectedState;
                break;
            case ScreenState.Move:
                _currentState = _moveState;
                break;
            case ScreenState.Moving:
                _currentState = _movingState;
                break;
            case ScreenState.Moved:
                _currentState = _movedState;
                break;
            case ScreenState.End:
                _currentState = _endState;
                break;
        }
        _currentState.ProcessState(this);
    }

    public void SetNewState(ScreenState state, MouseEventArgs args)
    {
        _args = args;
        var point = args.GetPosition(_window);
        SetNewState(state);
    }

    public string GetText(double offsetX = 0, double offsetY = 0)
    {
        Point leftTop = _window.clipRect.PointToScreen(new Point(0, 0));
        Point rightBottom = _window.clipRect.PointToScreen(new Point(_window.clipRect.ActualWidth, _window.clipRect.ActualHeight));

        double width = Math.Round(Math.Abs(rightBottom.X - leftTop.X) + offsetX);
        double height = Math.Round(Math.Abs(rightBottom.Y - leftTop.Y) + offsetY);

        return $"{leftTop}    {width}×{height}";
    }

    public bool IsInClipRect(Point point)
    {
        var relativePosition = point;
        if (relativePosition.X >= 0 && relativePosition.X <= _window.clipRect.ActualWidth &&
            relativePosition.Y >= 0 && relativePosition.Y <= _window.clipRect.ActualHeight)
        {
            return true;
        }
        return false;
    }
}

兩外XAML主界面的布局,就不給大家貼出來(lái),源代碼已經(jīng)上傳到github:https://github.com/caoruipeng123/ScreenApp

運(yùn)行效果

接下來(lái)看下實(shí)際的運(yùn)行效果:進(jìn)入截圖頁(yè)面之后,單擊鼠標(biāo)坐標(biāo)開(kāi)始框選截圖區(qū)域,雙擊鼠標(biāo)左鍵,可以結(jié)束截圖,并且圖片會(huì)設(shè)置到操作系統(tǒng)的粘貼板上,你可以把圖片粘貼到任何位置。

到此這篇關(guān)于WPF用狀態(tài)模式開(kāi)發(fā)截圖功能的文章就介紹到這了,更多相關(guān)WPF截圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#使用GDI繪制矩形的方法

    C#使用GDI繪制矩形的方法

    這篇文章主要介紹了C#使用GDI繪制矩形的方法,涉及C#使用GDI繪圖的相關(guān)技巧,需要的朋友可以參考下
    2015-04-04
  • .Net?Core以windows服務(wù)方式部署

    .Net?Core以windows服務(wù)方式部署

    這篇文章介紹了.Net?Core以windows服務(wù)方式部署,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-01-01
  • C#排序算法之快速排序解析

    C#排序算法之快速排序解析

    這篇文章主要為大家詳細(xì)介紹了C#排序算法之快速排序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-01-01
  • C# 中this關(guān)鍵字的主要作用

    C# 中this關(guān)鍵字的主要作用

    this 關(guān)鍵字在C#中主要用于引用當(dāng)前對(duì)象,區(qū)分字段與局部變量,調(diào)用其他構(gòu)造函數(shù)以及傳遞當(dāng)前對(duì)象給其他方法或構(gòu)造函數(shù),本文重點(diǎn)介紹C# this關(guān)鍵字的作用,感興趣的朋友一起看看吧
    2024-02-02
  • C#異步編程由淺入深(三)之詳解Awaiter

    C#異步編程由淺入深(三)之詳解Awaiter

    這篇文章主要介紹了C#異步編程由淺入深(三)之詳解Awaiter,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • C#?WPF調(diào)用QT窗口的方法

    C#?WPF調(diào)用QT窗口的方法

    本文主要介紹了C#?WPF調(diào)用QT窗口的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • c# 在windows中操作IIS設(shè)置FTP服務(wù)器的示例

    c# 在windows中操作IIS設(shè)置FTP服務(wù)器的示例

    這篇文章主要介紹了c# 在windows中操作IIS設(shè)置FTP服務(wù)器的示例,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-03-03
  • C#中將xml文件反序列化為實(shí)例時(shí)采用基類還是派生類的知識(shí)點(diǎn)討論

    C#中將xml文件反序列化為實(shí)例時(shí)采用基類還是派生類的知識(shí)點(diǎn)討論

    在本篇文章里小編給大家整理的是關(guān)于C#中將xml文件反序列化為實(shí)例時(shí)采用基類還是派生類的知識(shí)點(diǎn)討論,有需要的朋友們學(xué)習(xí)下。
    2019-11-11
  • c#初學(xué)簡(jiǎn)單程序?qū)嵗a介紹

    c#初學(xué)簡(jiǎn)單程序?qū)嵗a介紹

    這篇文章介紹了c#初學(xué)簡(jiǎn)單程序?qū)嵗a,有需要的朋友可以參考一下
    2013-10-10
  • C#實(shí)現(xiàn)標(biāo)題閃爍效果的示例代碼

    C#實(shí)現(xiàn)標(biāo)題閃爍效果的示例代碼

    在Windows系統(tǒng)中,當(dāng)程序在后臺(tái)運(yùn)行時(shí),如果某個(gè)窗體的提示信息需要用戶瀏覽,該窗體就會(huì)不停地閃爍,這樣就會(huì)吸引用戶的注意,下面我們就來(lái)看看如何使用C#實(shí)現(xiàn)這一效果吧
    2024-04-04

最新評(píng)論