Só posso responder pelo que funcionou para mim. Outros comentaristas apontaram que as GUIs do Java em geral se enquadram no 'vale misterioso' da aparência não muito nativa, e eu não discuto isso.
Faça bom uso da API de ação. Ele permite que você encapsule melhor as diferentes ações que seu usuário executará e permite conectá-las a atalhos, teclas aceleradoras, botões e outros objetos de entrada com muito mais facilidade.
Use um gerenciador de layout apropriado. O GridBagLayout é extremamente poderoso, mas eu diria que é impossível de manter, sem uma quantidade excessiva de comentários. Quando executo ferramentas de análise de código estático, como o Sonar, em um aplicativo GUI mais antigo que mantenho, ele sempre aponta grandes quantidades de números mágicos para tornar o layout do GridBags adequado. Eu tive muito sucesso com o GroupLayout, que evita precisar especificar o alinhamento perfeito de pixels.
Se você acha que precisa de um JDialog ... provavelmente não precisa . As caixas de diálogo são horríveis, em termos de experiência do usuário - esse aplicativo decidiu usá-las em todos os menus e formulários e aplicar regras sempre disponíveis de maneira bizarra. Isso se transformou em um pesadelo de manutenção quando, na verdade, precisamos alertar algo sobre o menu. Sugestão frustrada clicando em caixas de diálogo fora de foco - e, portanto, indissociáveis -.
Use o SwingWorker em vez de rolar seu próprio multithreading, onde apropriado. É muito fácil estender o SwingWorker e executar algumas tarefas demoradas, fornecendo atualizações regulares de volta à GUI. Pense em baixar uma atualização do cliente. Ele manipulará o agendamento de threads de trabalho para você e permitirá que você publique as porcentagens de download de volta à exibição, para que você possa atualizar sua ProgressBar ou o que você tem.
É tudo o que posso sugerir em minha experiência reconhecidamente limitada.