Em meu aplicativo, estou mudando constantemente de um controle para outro. Eu criei não. dos controles do usuário, mas durante a navegação meus controles piscam. leva 1 ou 2 segundos para atualizar. Eu tentei definir isso
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
or
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
mas não ajudou ... Cada controle tem a mesma imagem de fundo com controles diferentes. Então, qual é a solução para isso ..
Obrigado.
c#
winforms
user-controls
flicker
Royson
fonte
fonte
UpdateStyles
depois de definir isso? Está mal documentado, mas às vezes pode ser necessário.Respostas:
Não é o tipo de cintilação que o buffer duplo pode resolver. Nem BeginUpdate ou SuspendLayout. Você tem muitos controles, o BackgroundImage pode torná-lo muito pior.
Ele começa quando o UserControl se pinta. Ele desenha o BackgroundImage, deixando buracos onde vão as janelas de controle filho. Cada controle filho recebe uma mensagem para pintar a si mesmo, eles preencherão a lacuna com o conteúdo da janela. Quando você tem muitos controles, esses buracos ficam visíveis para o usuário por um tempo. Eles são normalmente brancos, contrastando mal com BackgroundImage quando está escuro. Ou podem ser pretos se o formulário tiver a propriedade Opacity ou TransparencyKey definida, contrastando mal com quase tudo.
Esta é uma limitação fundamental do Windows Forms, ela está presa na maneira como o Windows renderiza as janelas. Corrigido por WPF btw, ele não usa janelas para controles filho. O que você deseja é o buffer duplo de todo o formulário, incluindo os controles filhos. Isso é possível, verifique meu código neste segmento para a solução. Porém, tem efeitos colaterais e não aumenta a velocidade de pintura. O código é simples, cole no seu formulário (não no controle do usuário):
Há muitas coisas que você pode fazer para melhorar a velocidade de pintura, a ponto de a cintilação não ser mais perceptível. Comece abordando o BackgroundImage. Eles podem ser muito caros quando a imagem de origem é grande e precisa ser reduzida para caber no controle. Altere a propriedade BackgroundImageLayout para "Tile". Se isso fornecer uma aceleração perceptível, volte para o seu programa de pintura e redimensione a imagem para uma melhor correspondência com o tamanho de controle típico. Ou escreva o código no método OnResize () do UC para criar uma cópia de tamanho adequado da imagem para que ela não precise ser redimensionada toda vez que o controle redesenhar. Use o formato de pixel Format32bppPArgb para essa cópia, ele renderiza cerca de 10 vezes mais rápido do que qualquer outro formato de pixel.
A próxima coisa que você pode fazer é evitar que os buracos sejam tão perceptíveis e contrastem mal com a imagem. Você pode desativar o sinalizador de estilo WS_CLIPCHILDREN para o UC, o sinalizador que impede o UC de pintar na área onde os controles filhos vão. Cole este código no código do UserControl:
Os controles filhos agora vão se pintar no topo da imagem de fundo. Você ainda pode vê-los se pintando um por um, mas o feio buraco branco intermediário ou negro não será visível.
Por último, mas não menos importante, reduzir o número de controles filho é sempre uma boa abordagem para resolver problemas de pintura lenta. Substitua o evento OnPaint () do UC e desenhe o que agora é mostrado em um filho. Rótulo específico e PictureBox são muito desperdiçadores. Conveniente para apontar e clicar, mas sua alternativa leve (desenhar uma string ou uma imagem) leva apenas uma única linha de código em seu método OnPaint ().
fonte
Este é um problema real, e a resposta que Hans Passant deu é ótima para salvar a cintilação. No entanto, há efeitos colaterais, como ele mencionou, e eles podem ser feios (IU feia). Conforme declarado, "Você pode desligar o
WS_CLIPCHILDREN
sinalizador de estilo para a UC", mas isso só o desativa para uma UC. Os componentes do formulário principal ainda apresentam problemas.Por exemplo, uma barra de rolagem do painel não pinta, porque está tecnicamente na área filho. No entanto, o componente filho não desenha a barra de rolagem, então ela não é pintada até que o mouse passe (ou outro evento o acione).
Além disso, os ícones animados (alterando ícones em um loop de espera) não funcionam. Remover ícones em um
tabPage.ImageKey
não redimensiona / redesenha as outras páginas da guia apropriadamente.Então, eu estava procurando uma maneira de desligar a
WS_CLIPCHILDREN
pintura inicial para que meu Form carregue bem pintado, ou melhor ainda, apenas ligue-o enquanto redimensiona meu formulário com muitos componentes.O truque é fazer com que o aplicativo chame
CreateParams
com oWS_EX_COMPOSITED/WS_CLIPCHILDREN
estilo desejado . Encontrei um hack aqui ( https://web.archive.org/web/20161026205944/http://www.angryhacker.com/blog/archive/2010/07/21/how-to-get-rid-of- flicker-on-windows-forms-applications.aspx ) e funciona muito bem. Obrigado AngryHacker!Eu coloco a
TurnOnFormLevelDoubleBuffering()
chamada noResizeBegin
evento de formulário eTurnOffFormLevelDoubleBuffering()
chamo o evento ResizeEnd do formulário (ou apenas o deixoWS_CLIPCHILDREN
depois que ele é inicialmente pintado corretamente).fonte
Se você estiver fazendo qualquer pintura personalizada no controle (ou seja, substituindo OnPaint), você mesmo pode tentar o buffer duplo.
E invalidar seu controle com uma propriedade
NeedRepaint
Caso contrário, a resposta acima com SuspendLayout e ResumeLayout é provavelmente o que você deseja.
fonte
if (image != null) image.Dispose();
antesimage = new Bitmap...
Tente os métodos BeginUpdate / EndUpdate OU SuspendLayout / ResumeLayout. Veja a seguir
Como corrigir problemas de oscilação de controle de winform aninhado Tremulação
durante atualizações de controles em WinForms (por exemplo, DataGridView)
fonte
No formulário principal ou controle do usuário onde a imagem de fundo reside, defina a
BackgroundImageLayout
propriedade comoCenter
ouStretch
. Você notará uma grande diferença quando o controle do usuário estiver renderizando.fonte
Tentei adicionar isso como um comentário, mas não tenho pontos suficientes. Esta é a única coisa que ajudou meus problemas intermitentes, muito obrigado a Hans por sua postagem. Para qualquer um que esteja usando o c ++ builder como eu, aqui está a tradução
Adicione a declaração CreateParams ao arquivo .h do formulário principal do seu aplicativo, por exemplo
e adicione isso ao seu arquivo .cpp
fonte
Coloque o código abaixo em seu construtor ou evento OnLoad e se você estiver usando algum tipo de controle de usuário personalizado com subcontroles, você precisará certificar-se de que esses controles personalizados também tenham buffer duplo (embora na documentação da MS eles digam é definido como verdadeiro por padrão).
Se você estiver fazendo um controle personalizado, convém adicionar este sinalizador em seu ctor:
Opcionalmente, você pode usar este código em seu formulário / controle:
Nós iteramos por todos os controles no formulário / controle e acessamos suas
DoubleBuffered
propriedades e então mudamos para verdadeiro a fim de tornar cada controle no formulário em buffer duplo. A razão de fazermos reflexão aqui é porque imagine que você tem um controle que possui controles filhos que não são acessíveis, dessa forma, mesmo que sejam controles privados, ainda alteraremos sua propriedade para true.Mais informações sobre a técnica de buffer duplo podem ser encontradas aqui .
Há outra propriedade que geralmente substituo para resolver esse problema:
WS_EX_COMPOSITED
- Pinta todos os descendentes de uma janela na ordem de pintura de baixo para cima usando buffer duplo.Você pode encontrar mais desses sinalizadores de estilo aqui .
Espero que ajude!
fonte
Só para acrescentar à resposta que Hans deu:
(Versão TLDR: a transparência é mais pesada do que você pensa, use apenas cores sólidas em todos os lugares)
Se WS_EX_COMPOSITED, DoubleBuffered e WS_CLIPCHILDREN não resolveram seu flicker (para mim WS_CLIPCHILDREN tornou ainda pior), tente isto: passe por TODOS os seus controles e todo o seu código, e onde quer que você tenha Qualquer transparência ou semitransparência para BackColor, ForeColor ou qualquer outra cor, basta removê-la, usar apenas cores sólidas. Na maioria dos casos em que você acha que só precisa usar transparência, não o faz. Reprojete seu código e controles e use cores sólidas. Tive uma tremulação terrível e terrível e o programa estava lento. Depois de remover a transparência, ela aumentou significativamente e não há oscilação.
EDIT: Para adicionar mais, acabei de descobrir que WS_EX_COMPOSITED não precisa ser de toda a janela, ele pode ser aplicado apenas a controles específicos! Isso me salvou de muitos problemas. Basta fazer um controle customizado herdado de qualquer controle de que você precisa e colar a substituição já postada para WS_EX_COMPOSITED. Desta forma, você obtém buffer duplo de baixo nível apenas neste controle, evitando os efeitos colaterais desagradáveis no resto do aplicativo!
fonte
Sei que essa pergunta é muito antiga, mas quero passar minha experiência sobre ela.
Eu tive muitos problemas com
Tabcontrol
cintilação em um formulário com substituídoOnPaint
e / ouOnPaintBackGround
no Windows 8 usando .NET 4.0.A única coisa que funcionou foi NÃO USAR o
Graphics.DrawImage
método emOnPaint
overrides, ou seja, quando o desenho foi feito diretamente nos Gráficos fornecidos pelaPaintEventArgs
, mesmo pintando todo o retângulo, a cintilação desapareceu. Mas se chamar oDrawImage
método, mesmo desenhando um bitmap recortado (criado para buffer duplo), a cintilação aparece.Espero que ajude!
fonte
Combinei esta correção de oscilação e esta correção de fonte , então tive que adicionar um pouco do meu próprio código para iniciar um cronômetro na pintura para invalidar o TabControl quando ele sai da tela e volta, etc.
Todos os três fazem isso:
Eu não sou o criador, mas pelo que entendi, o bitmap faz todo o desvio de bug.
Esta foi a única coisa que resolveu definitivamente a cintilação do TabControl (com ícones) para mim.
vídeo de resultado de diferença: vanilla tabcontrol vs tabcontrolex
http://gfycat.com/FineGlitteringDeermouse
ps. você precisará definir HotTrack = true, porque isso também corrige o bug
fonte
Você tentou a
Control.DoubleBuffered
propriedade?Também isso e isso podem ajudar.
fonte
Não há necessidade de nenhum buffer duplo e todas essas coisas caras ...
Uma solução simples ...
Se você estiver usando a interface MDI, basta colar o código abaixo no formulário principal. Isso removerá todas as cintilações das páginas. No entanto, algumas páginas que requerem mais tempo para carregar aparecerão em 1 ou 2 segundos. Mas isso é melhor do que mostrar uma página piscando em que cada item vem um por um.
Esta é a única melhor solução para toda a aplicação. Veja o código para colocar no formulário principal:
fonte