STNodeEditor icon indicating copy to clipboard operation
STNodeEditor copied to clipboard

关于NodeProperty面板和Node控件同步更新的问题

Open CS-LX opened this issue 3 years ago • 1 comments

你好,我遇到了一个问题 在NodeProperty里更改了节点的某一个属性,但是在节点那边好像不能同步更新 我在节点里加了一个enum,并打上了STNodeProperty标记,还在节点上搞了个控件,可以在节点中显示并且更改这个enum,总的来说我既可以在NodeProperty里面更改这个enum,也可以通过节点上的控件更改这个enum。 但是现在就出现了一个问题,我在NodeProperty里更改了这个enum的值,但是节点上的控件不能同步更新(显示的还是更改前的enum),我必须把鼠标移上节点它才能更新。并且我通过节点上的控件更改了enum的值,但是NodeProperty也不能同步更新,我必须把鼠标移上NodeProperty面板它才会更新。 我很想做成节点和NodeProperty同步更新的效果,但是我尝试了很久都没有效果...请问我该怎么做?

这是enum

    public enum ImageBlendMode
    {
        /// <summary>
        /// 变暗
        /// </summary>
        Darken = 1,
        /// <summary>
        /// 正片叠底
        /// </summary>
        Multiply = 0,
        /// <summary>
        /// 颜色加深
        /// </summary>
        ColorBurn = 2,
        /// <summary>
        /// 线性加深
        /// </summary>
        LinearBurn = 3,
        /// <summary>
        /// 变亮
        /// </summary>
        Lighten = 4,
        /// <summary>
        /// 滤色模式
        /// </summary>
        Screen = 5,
        /// <summary>
        /// 颜色减淡
        /// </summary>
        ColorDodge = 6,
        /// <summary>
        /// 线性减淡
        /// </summary>
        LinearDodge = 7,
        /// <summary>
        /// 叠加模式
        /// </summary>
        Overlay = 8,
    }

这是我写的对应控件

    public class STMultiSelectBox : STNodeControl
    {
        private bool m_b_enter;
        private bool m_b_l;
        private bool m_b_r;
        private bool m_b_down;
        private int index = 0;
        private int switchButtonWidth = 16;

        private Dictionary<int, string> options = new Dictionary<int, string>();
        public Dictionary<int, string> Options
        {
            get { return options; }
            set { options = value; }
        }
        public int SwitchButtonWidth
        {
            get { return switchButtonWidth; }
            set { switchButtonWidth = value; }
        }
        public int Index
        {
            get { return index; }
            set { index = value; }
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            m_b_enter = true;
            this.Invalidate();
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            m_b_l = false; m_b_r = false;
            m_b_enter = false;
            this.Invalidate();
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            m_b_down = true;
            this.Invalidate();
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (m_b_r)
            {
                if (index < options.Count - 1) index++;
                else index = 0;
            }
            else if (m_b_l)
            {
                if (index > 0) index--;
                else index = options.Count - 1;
            }
            base.OnMouseUp(e);
            m_b_down = false;
            this.Invalidate();
        }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            m_b_l = false; m_b_r = false;
            if (e.Location.X <= switchButtonWidth) m_b_l = true;
            if (e.Location.X >= Width - switchButtonWidth) m_b_r = true;
            this.Invalidate();
        }

        protected override void OnPaint(DrawingTools dt)
        {
            index = Mathf.Clamp(index, 0, options.Count - 1);
            //base.OnPaint(dt);
            Graphics g = dt.Graphics;
            SolidBrush brush = dt.SolidBrush;
            brush.Color = this.BackColor;
            g.FillRectangle(brush, 0, 0, this.Width, this.Height);//绘制背景黑色

            //鼠标移上背景变量
            brush.Color = NodeControlsColor.ColorDark;
            if (m_b_enter) g.FillRectangle(brush, 0, 0, this.Width, this.Height);//绘制背景黑色
            //绘制鼠标移上两边按钮
            brush.Color = m_b_down ? NodeControlsColor.ActivitiveColorLight : NodeControlsColor.ActivitiveColorDark;//不按下偏白的灰色,按下亮蓝色
            if (m_b_l) g.FillRectangle(brush, 0, 0, switchButtonWidth, this.Height);
            if (m_b_r) g.FillRectangle(brush, Width - switchButtonWidth, 0, switchButtonWidth, this.Height);
            //绘制三角形
            Point centerL = new Point(switchButtonWidth / 2, Height / 2);
            Point centerR = new Point(((Width - switchButtonWidth) + Width) / 2, Height / 2);
            //左边
            Point pointTopL = new Point(centerL.X - 3, centerL.Y);
            Point pointBot1L = new Point(centerL.X + 3, centerL.Y + 6);
            Point pointBot2L = new Point(centerL.X + 3, centerL.Y - 6);
            brush.Color = m_b_enter ? NodeControlsColor.ActivitiveColorWhite : NodeControlsColor.ActivitiveColorDark;
            g.FillPolygon(brush, new Point[] { pointTopL, pointBot1L, pointBot2L });
            //右边
            Point pointTopR = new Point(centerR.X + 3, centerR.Y);
            Point pointBot1R = new Point(centerR.X - 3, centerR.Y + 6);
            Point pointBot2R = new Point(centerR.X - 3, centerR.Y - 6);
            brush.Color = m_b_enter ? NodeControlsColor.ActivitiveColorWhite : NodeControlsColor.ActivitiveColorDark;
            g.FillPolygon(brush, new Point[] { pointTopR, pointBot1R, pointBot2R });

            g.DrawString($"{Text}:{options[index]}", new Font("courier new", 7f), !m_b_enter ? Brushes.LightGray : Brushes.White, new Rectangle(0, 2, Width, Height), base.m_sf);//绘制颜色
        }
    }

然后这是节点

    public class ColorBlendImageNode : STNode
    {
        private STNodeOption m_op_in_imageBase;
        private STNodeOption m_op_in_imageBlend;
        private STNodeOption m_op_in_fac;
        private STNodeOption m_op_out;

        private STImageBox imageBox;
        private STMultiSelectBox selectBox;

        [STNodeProperty("模式", "")]
        public ImageBlendMode mode
        {
            get
            {
                return (ImageBlendMode)selectBox.Index;
            }
            set
            {
                selectBox.Index = (int)value;
                OutImage();
            }
        }
        protected override void OnCreate()
        {
            base.OnCreate();
            this.Title = "颜色混合";
            this.Tag = "解析/转换";
            this.ItemHeight = 30;
            this.TitleHeight = 30;
            this.TitleColor = Color.FromArgb(200, Color.GreenYellow);
            this.AutoSize = false;
            this.Size = new Size(190 + 10 * 2, 10 + ItemHeight * 3 + 190 + TitleHeight + 35);

            m_op_in_imageBase = this.InputOptions.Add("基图像", typeof(Image), true);
            m_op_in_imageBlend = this.InputOptions.Add("混合图像", typeof(Image), true);
            m_op_in_fac = this.InputOptions.Add("系数", typeof(float), true);

            m_op_out = this.OutputOptions.Add("输出", typeof(Image), false);

            m_op_in_imageBase.DataTransfer += new STNodeOptionEventHandler(m_op_in_DataTransfer);
            m_op_in_imageBlend.DataTransfer += new STNodeOptionEventHandler(m_op_in_DataTransfer);
            m_op_in_fac.DataTransfer += new STNodeOptionEventHandler(m_op_in_DataTransfer);

            selectBox = new STMultiSelectBox();
            selectBox.Location = new Point(10, 5 + ItemHeight * 3);
            selectBox.Size = new Size(190, 30);
            selectBox.Text = "混合模式";
            selectBox.Options.Add(0, "正片叠底");
            selectBox.Options.Add(1, "变暗");
            selectBox.Options.Add(2, "颜色加深");
            selectBox.Options.Add(3, "线性加深");
            selectBox.Options.Add(4, "变亮");
            selectBox.Options.Add(5, "滤色");
            selectBox.Options.Add(6, "颜色减淡");
            selectBox.Options.Add(7, "线性减淡");
            selectBox.Options.Add(8, "叠加");

            selectBox.MouseUp += new MouseEventHandler(selectBox_MouseUp);

            imageBox = new STImageBox();
            imageBox.Location = new Point(10, 5 + ItemHeight * 3 + 35);
            imageBox.Size = new Size(190, 190);

            this.Controls.Add(imageBox);
            this.Controls.Add(selectBox);

            m_op_in_fac.Data = 1f;
        }
        //无论AutoSize为何值 都可以对选项连接点位置进行修改

        protected override Point OnSetOptionDotLocation(STNodeOption op, Point pt, int nIndex)
        {
            //if (op == m_op_out_x) return new Point(pt.X, pt.Y + ItemHeight);
            //if (op == m_op_out_y) return new Point(pt.X, pt.Y + ItemHeight);
            return base.OnSetOptionDotLocation(op, pt, nIndex);
        }
        protected override Rectangle OnSetOptionTextRectangle(STNodeOption op, Rectangle rect, int nIndex)
        {
            //if (op == m_op_out_x) return new Rectangle(rect.X, rect.Y + ItemHeight, rect.Width, rect.Height);
            //if (op == m_op_out_y) return new Rectangle(rect.X, rect.Y + ItemHeight, rect.Width, rect.Height);
            return base.OnSetOptionTextRectangle(op, rect, nIndex);
        }

        void OutImage()
        {
            if (m_op_in_imageBase.Data != null && m_op_in_imageBlend.Data != null)
            {
                Bitmap bitmapBase = new Bitmap((Image)m_op_in_imageBase.Data);
                Bitmap bitmapBlend = new Bitmap((Image)m_op_in_imageBlend.Data);
                float fac = (float)m_op_in_fac.Data;

                Bitmap bitmap = ImageTool.ColorBlending(bitmapBase, bitmapBlend, fac, mode);
                m_op_out.TransferData(bitmap);
                imageBox.Image = bitmap;
                //File.Delete(Application.StartupPath + "\\Cache\\CacheBitmap.png");
            }
        }

        void selectBox_MouseUp(object sender, MouseEventArgs e)
        {
            OutImage();
        }
        void m_op_in_DataTransfer(object sender, STNodeOptionEventArgs e)
        {
            try
            {
                if (e.Status != ConnectionStatus.Connected || e.TargetOption.Data == null)
                {
                    if (sender == m_op_in_imageBase) m_op_in_imageBase.Data = null;
                    if (sender == m_op_in_imageBlend) m_op_in_imageBlend.Data = null;
                    if (sender == m_op_in_fac) m_op_in_fac.Data = 1f;
                    m_op_out.TransferData(null);
                }
                else
                {
                    if (sender == m_op_in_imageBase) m_op_in_imageBase.Data = e.TargetOption.Data;
                    if (sender == m_op_in_imageBlend) m_op_in_imageBlend.Data = e.TargetOption.Data;
                    if (sender == m_op_in_fac) m_op_in_fac.Data = e.TargetOption.Data;
                }
                OutImage();
            }
            catch (Exception ex)
            {
                UsefulMethods.ShowError(ex);
            }
        }
    }

CS-LX avatar Jan 02 '23 02:01 CS-LX

是的 你说的这个问题一直存在,原因也很简单。。属性框设置属性后,Node是并不知道被设置了属性了,,要解决这个问题好说,,只要修改属性框的代码 一旦设置了值管他三七二十一 直接调用节点的重绘函数即可。。但是 反过来就有点麻烦了,,Node并不知道自己是被属性框给加载了的,,所以它的属性背改变的时候不知道怎么去通知属性框重绘,如果要解决的话就需要额外的代码弄一个私有的List<STNodePropertyGrid>配合属性框,用来保存被那些属性框给加载了,,一旦值发生变化就通知属性框重绘制。。但是这样的代码写进Node里面觉得似乎有些多余,,因为对于用户来说 属性框并不是必须的。。而且有一些用户是用的自己编写的TreeView和PropertyGrid。。而且还有一个很麻烦的问题。。就是需要监控属性的Getter和Setter。。不然无法知道属性值被修改了。。不然只能通过用户自己在属性的Set里面编写代码去通知属性框。

当时发现这个问题的时候 我也想了一会儿 要不要解决掉这个问题。。然后就搁置了。。。。。

DebugST avatar Jan 03 '23 02:01 DebugST