Как предотвратить замедление фонового изображения в приложении C # Windows Form при изменении текста [дубликат]

Я попытаюсь объяснить вам, что это за ошибка. Начиная с MySQL 5.7.5, опция ONLY_FULL_GROUP_BY включена по умолчанию. Таким образом, согласно стандарту SQL92 и ранее:

не разрешает запросы, для которых список выбора, условие HAVING или список ORDER BY относятся к неагрегированным столбцам, которые не имеют ни имени в предложении GROUP BY, ни функционально зависимы от (однозначно определенных) столбцами GROUP BY

blockquote>

( подробнее в документах )

Итак, например:

SELECT * FROM `users` GROUP BY `name`;

После выполнения запроса вы получите сообщение об ошибке.

# 1055 - Выражение # 1 списка SELECT не находится в предложении GROUP BY и содержит неагрегированный столбец «testite». user.id ', который функционально не зависит от столбцов в предложении GROUP BY; это несовместимо с sql_mode = only_full_group_by

blockquote>

Почему? Поскольку MySQL точно не понимает, какие определенные значения из сгруппированных записей извлекаются, и это точка.

I.E. скажем, у вас есть эти записи в вашей таблице users:

И вы выполните недопустимый запрос, показанный выше. И вы получите ошибку, показанную выше, потому что есть 3 записи с именем John, и это хорошо, но все они имеют разные значения полей email. Таким образом, MySQL просто не понимает, какие из них возвращаются в результирующую сгруппированную запись.

Вы можете исправить эту проблему, просто изменив свой запрос следующим образом:

SELECT `name` FROM `users` GROUP BY `name`

Также , вы можете захотеть добавить больше полей в секцию SELECT, но вы не можете это сделать, если они не агрегированы, но есть костыль, который вы могли бы использовать (но сильно не рекомендовано):

SELECT ANY_VALUE(`id`), ANY_VALUE(`email`), `name` FROM `users` GROUP BY `name`

Теперь вы можете спросить, почему использование ANY_VALUE настоятельно не рекомендуется? Поскольку MySQL точно не знает, какое значение сгруппированных записей извлекается, и с помощью этой функции вы просите ее получить любую из них (в этом случае было отправлено электронное письмо первой записи с именем = John). Именно я не могу придумать какие-либо идеи о том, почему вы хотите, чтобы это поведение существовало. Пожалуйста, если вы меня не понимаете, читайте больше о том, как работает группировка в MySQL, это очень просто.

И к концу, вот еще один простой, но действительный запрос. Если вы хотите запросить общий подсчет пользователей в соответствии с доступными возрастами, вы можете записать этот запрос

SELECT `age`, COUNT(`age`) FROM `users` GROUP BY `age`;

, который является полностью действительным, в соответствии с правилами MySQL. И так далее. Важно понять, в чем проблема, и только потом записать решение.

56
задан BigBug 18 January 2013 в 19:27
поделиться

13 ответов

Наконец решил мерцание. Поскольку я рисовал панель вместо формы, строка кода ниже не решит мерцание:

this.SetStyle(
    ControlStyles.AllPaintingInWmPaint | 
    ControlStyles.UserPaint | 
    ControlStyles.DoubleBuffer, 
    true);

SetStyle должен иметь тип «YourProject.YourProject» (или полученный из него), следовательно, вам нужно создать класс как таковой (чтобы вы могли использовать MyPanel, который будет получен из SPaint.SPaint и, следовательно, позволяет вам использовать двойной буферизм непосредственно для панели, а не в форме):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SPaint; 

namespace YourProject
{
    public class MyPanel : System.Windows.Forms.Panel
    {
        public MyPanel()
        {
            this.SetStyle(
                System.Windows.Forms.ControlStyles.UserPaint | 
                System.Windows.Forms.ControlStyles.AllPaintingInWmPaint | 
                System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer, 
                true);
        }
    }
}

После того, как вы это сделали (хотя вам действительно не нужно редактировать код дизайнера, если вы действительно не знаете, что делаете), вам нужно будет отредактировать форму.Designer.cs. Внутри этого файла вы найдете код, который выглядит следующим образом:

this.panelArea = new YourProject.MyPanel();

Вышеупомянутая строка должна быть изменена на:

this.panelArea = new MyPanel(); 

После выполнения этих шагов моя программа рисования больше не мерцает.

Для всех, кто имеет такую ​​же проблему, проблема окончательно решена.

Наслаждайтесь!

50
ответ дан Masoud 4 September 2018 в 07:26
поделиться

Попробуйте вставить схему рисования в метод текущей формы

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
}

. В этом случае вы должны использовать параметр e для получения объекта Graphics. Используйте свойство e.Graphics. Затем вы должны вызывать метод Invalidate () для этой формы всякий раз, когда форма должна быть перерисована. PS: DoubleBuffered должен быть установлен в true.

0
ответ дан DeeDee 4 September 2018 в 07:26
поделиться

, если все вышеописанное не работает, вы всегда можете создать свою собственную двойную буферную ссылку на учебник Microsoft: https://docs.microsoft.com/en-us/dotnet/framework/winforms/advanced/

надеется, что он сработает для вас

0
ответ дан Jan Tamis Kossen 4 September 2018 в 07:26
поделиться

Скопируйте и вставьте это в свой проект

protected override CreateParams CreateParams
{
    get
    {
        CreateParams handleParam = base.CreateParams;
        handleParam.ExStyle |= 0x02000000;   // WS_EX_COMPOSITED       
        return handleParam;
    }
}

Это позволяет выполнять двойную буферизацию для всех элементов управления с уровня формы вниз, в противном случае для каждой из них необходимо индивидуально активировать двойную буферизацию ... вы можете хотите точно настроить двойное буферизацию после этого, потому что двойная буферизация с заполнением может дать нежелательные побочные эффекты.

23
ответ дан M. Schena 4 September 2018 в 07:26
поделиться

Я бы посоветовал переопределить OnPaintBackground и обработать фоновое стирание самостоятельно. Если вы знаете, что рисуете весь элемент управления, вы можете просто ничего не делать в OnPaintBackground (не называйте базовый метод), и это предотвратит окрашивание цвета фона сначала

2
ответ дан Matt 4 September 2018 в 07:26
поделиться

здесь программа перемещения круга в .net, которая не мерцает.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
namespace CircleMove
{
    /// <summary>
    /// Description of MainForm.
    /// </summary>
    public partial class MainForm : Form
    {
        int x=0,y=0;
        Thread t;

        public MainForm()
        {

            //
            // The InitializeComponent() call is required for Windows Forms designer support.
            //
            InitializeComponent();

            //
            // TODO: Add constructor code after the InitializeComponent() call.
            //
        }
        void MainFormPaint(object sender, PaintEventArgs e)
        {
            Graphics g=e.Graphics;
            Pen p=new Pen(Color.Orange);
            Brush b=new SolidBrush(Color.Red);
        //  g.FillRectangle(b,0,0,100,100);
            g.FillEllipse(b,x,y,100,100);
        }
        void MainFormLoad(object sender, EventArgs e)
        {
            t=new Thread(  new ThreadStart(

                ()=>{
                    while(true)
                    {
                        Thread.Sleep(10);
                        x++;y++;
                        this.Invoke(new Action(
                            ()=>{

                                this.Refresh();
                                this.Invalidate();
                                this.DoubleBuffered=true;
                                }
                                            )
                                        );
                    }
                    }
                                            )

                        );

            t.Start();
        }
    }
}
1
ответ дан sanjay 4 September 2018 в 07:26
поделиться

Можете ли вы попытаться использовать таймер и логическое значение, чтобы проверить, не указана ли мышь, и нарисовать в этом месте, используя переменную, снова проверьте, переместил ли пользователь свою мышь, если переместить краску в это место и т. д.

Или просто проверьте, нажата ли мышь (через boolean, которая устанавливает true, когда мышь не работает), используя таймер и нарисуйте его, учитывая, что вы, вероятно, пытаетесь просто нарисовать один пиксель, а не как тень и т. Д. Вместо использования фактического mousedown. Таким образом, вы проверяете каждую секунду вместо 0.0001, и это не мерцает. Или наоборот, попробуйте в свое время.

-1
ответ дан Stormturtle 4 September 2018 в 07:26
поделиться

Я знаю, что это действительно старый вопрос, но, возможно, кто-то найдет его полезным. Я хотел бы немного улучшить ответ viper.

Вы можете сделать простое расширение классом Panel и скрыть свойство настройки через отражение.

public static class MyExtensions {

    public static void SetDoubleBuffered(this Panel panel) {
        typeof(Panel).InvokeMember(
           "DoubleBuffered",
           BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty,
           null,
           panel,
           new object[] { true });
    }
}

Если имя переменной вашей панели myPanel вы можете просто вызвать myPanel.SetDoubleBuffered (); вот и все. Код выглядит намного чище.

3
ответ дан thorgil 4 September 2018 в 07:26
поделиться

Двойная буферизация здесь не поможет. Я боюсь. Я столкнулся с этим некоторое время назад и в итоге добавил отдельную панель довольно неуклюжим способом, но это сработало для моего приложения.

Сделайте панель с оригинальной панелью (панель) прозрачной областью и поставьте ее поверх второй панели, которую вы вызываете, например, panelDraw. Убедитесь, что панель впереди. Я взбесил это, и он избавился от мерцания, но оставил форму, которая была нарисована, поэтому она не является полным решением.

Прозрачная панель может быть выполнена путем переопределения некоторых действий с краской Исходная панель:

public class ClearPanel : Panel
{
    public ClearPanel(){}

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams createParams = base.CreateParams;
            createParams.ExStyle |= 0x00000020;
            return createParams;
        }
    }

    protected override void OnPaintBackground(PaintEventArgs e){}
}

Идея состоит в том, чтобы обрабатывать рисование временной фигуры во время события MouseMove в панели panelArea и ТОЛЬКО перерисовать «panelDraw» на MouseUp Event.

// Use the panelDraw paint event to draw shapes that are done
void panelDraw_Paint(object sender, PaintEventArgs e)
{
    Graphics g = panelDraw.CreateGraphics();

    foreach (Rectangle shape in listOfShapes)
    {
        shape.Draw(g);
    }
}

// Use the panelArea_paint event to update the new shape-dragging...
private void panelArea_Paint(object sender, PaintEventArgs e)
{
    Graphics g = panelArea.CreateGraphics();

    if (drawSETPaint == true)
    {
        Pen p = new Pen(Color.Blue);
        p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;

        if (IsShapeRectangle == true)
        {
            g.DrawRectangle(p, rect);
        }
        else if (IsShapeCircle == true)
        {
            g.DrawEllipse(p, rect);
        }
        else if (IsShapeLine == true)
        {
            g.DrawLine(p, startPoint, endPoint);
        }
    }
}

private void panelArea_MouseUp(object sender, MouseEventArgs e)
{

    endPoint.X = e.X;
    endPoint.Y = e.Y;

    drawSETPaint = false;

    if (rect.Width > 0 && rect.Height > 0)
    {
        if (IsShapeRectangle == true)
        {
            listOfShapes.Add(new TheRectangles(rect, currentColor, currentBoarderColor, brushThickness));
        }
        else if (IsShapeCircle == true)
        {
            listOfShapes.Add(new TheCircles(rect, currentColor, currentBoarderColor, brushThickness));
        }
        else if (IsShapeLine == true)
        {
            listOfShapes.Add(new TheLines(startPoint, endPoint, currentColor, currentBoarderColor, brushThickness));
        }

        panelArea.Invalidate();
    }

    panelDraw.Invalidate();
}
3
ответ дан Tom 4 September 2018 в 07:26
поделиться

Если память плотная (так что вы не хотите, чтобы стоимость памяти была двойной буферизацией), один из возможных способов уменьшить, хотя и не устранить, мерцание - это установить цвет фона для доминирующего цвета в вашей текущей сцене.

Почему это помогает: мерцание - это мгновенная вспышка цвета фона, которую ОС рисует перед рисованием дочерних элементов управления или вашего пользовательского кода рисования. Если эта вспышка является цветом, который ближе к окончательному цвету, который будет отображаться, он будет менее заметным.

Если вы не знаете, с какого цвета начать, начните с 50% серого, потому что это в среднем черно-белый, поэтому будет ближе к большинству цветов в вашей сцене.

myFormOrControl.BackColor = Color.Gray;
0
ответ дан ToolmakerSteve 4 September 2018 в 07:26
поделиться

В этом условии вы должны включить двойной буфер. Откройте текущую форму и перейдите к свойствам формы и примените двойной буфер true; или вы также можете написать этот код.

this.DoubleBuffered = true;     

В загрузке формы.

1
ответ дан user 4 September 2018 в 07:26
поделиться

У меня была та же проблема. Я никогда не мог на 100% избавиться от мерцания (см. Пункт 2), но я использовал это

protected override void OnPaint(PaintEventArgs e) {}

, а также

this.DoubleBuffered = true;

. Основная проблема для мерцания убедитесь, что вы

  1. красите вещи в правильном порядке!
  2. убедитесь, что ваша функция рисования равна & lt; около 1/60 секунды

winforms вызывает метод OnPaint каждый раз, когда форму нужно перерисовать. Есть много способов, которыми это может быть девальвацией, в том числе перемещение курсора мыши над формой иногда может вызвать событие перерисовывания.

И важно отметить OnPaint, что вы не начинаете с нуля каждый раз, вы вместо этого начинаете с того места, где вы были, если вы заливаете цвет фона, вы, вероятно, будете мерцать.

Наконец, ваш объект gfx. Внутри OnPaint вам нужно будет воссоздать графический объект, но ТОЛЬКО, если размер экрана изменился. воссоздание объекта очень дорого, и его нужно утилизировать до его воссоздания (сбор мусора не на 100% обрабатывает его правильно или так говорит документация). Я создал переменную класса

protected Graphics gfx = null;

, а затем использовал ее локально в OnPaint, как это было, но это было потому, что мне нужно было использовать объект gfx в других местах моего класса. В противном случае НЕ ДЕЛАЙТЕ ЭТО. Если вы только рисуете в OnPaint, пожалуйста, используйте e.Graphics !!

// clean up old graphics object
gfx.Dispose();

// recreate graphics object (dont use e.Graphics, because we need to use it 
// in other functions)
gfx = this.CreateGraphics();

Надеюсь, что это поможет.

13
ответ дан Uwe Keim 4 September 2018 в 07:26
поделиться

Для «чистого решения» и для того, чтобы продолжать использовать базовую панель, вы можете просто использовать Reflection для реализации двойной буферизации, добавив этот код в форму, содержащую панели, в которые вы хотите вставить

    typeof(Panel).InvokeMember("DoubleBuffered", 
    BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic, 
    null, DrawingPanel, new object[] { true });

Где «DrawingPanel» - это название панели, в которой вы хотите выполнить двойную буферизацию.

Я знаю, что прошло много времени с тех пор, как был задан вопрос, но это может помочь кому-то в будущем.

49
ответ дан viper 4 September 2018 в 07:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: