Flutter for Windows Desktop: Getting Started
Learn how to set up a development environment and create a simple Flutter calculator app for Windows Desktop. By Karol Wrótniak.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Flutter for Windows Desktop: Getting Started
20 mins
- Getting Started
- Installing Visual Studio
- Enabling Desktop Support in Flutter
- Creating the Project
- Developing the Button
- Developing the Grid of Buttons
- Building the Business Logic
- Developing the Calculation Engine
- Binding UI with Business Logic
- Developing Features for Desktop
- Supporting Mouse Input
- Supporting Keyboard Input
- Handling Keystrokes
- Handling Key Events
- Managing Window Size
- Preventing Window Maximization
- Integrating with System Clipboard
- Polishing the Project
- Where to Go From Here
Managing Window Size
The application window concept doesn’t exist natively in Flutter. You have to handle it separately for each platform. You can change the platform-specific files generated by Flutter in the windows folder, but it’s more convenient to operate from the Dart code. You can do that using the window_manager plugin. The plug-in takes care of executing OS-specific actions. It also supports desktop platforms other than Windows. Add the dependency:
fluter pub add window_manager
The calculator view should always be in portrait orientation (a vertically oriented rectangle). Moreover, you need reasonable minimum and maximum sizes so the layout doesn’t break. You can enforce those restrictions before calling runApp
in the main.dart
file:
import 'package:window_manager/window_manager.dart';
import 'package:flutter/material.dart';
import 'calculator_body.dart';
Future<void> main() async {
//1
WidgetsFlutterBinding.ensureInitialized();
await windowManager.ensureInitialized();
//2
await windowManager.setMinimumSize(const Size(309, 600));
await windowManager.setMaximumSize(const Size(618, 1200));
await windowManager.setSize(const Size(309, 600));
await windowManager.setAspectRatio(0.54);
await windowManager.setMaximizable(false);
await windowManager.setTitle('FCalc');
//3
runApp(const FCalcApp());
}
class FCalcApp extends StatelessWidget {
const FCalcApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) =>
MaterialApp(home: Scaffold(body: CalculatorBody()));
}
Here is what the code above does:
- Initializes the Flutter and window manager internals.
- Sets window properties such as a size, aspect ratio and title.
- Starts the app.
Remember that all the window_manager
methods are asynchronous. So you have to add await
s to wait until they finish working.
Preventing Window Maximization
setMaximumSize
is effective only when changing window size, but users can still maximize a window using a system menu bar. You have to disable maximization by calling setMaximizable(false)
.
Note that the window_manager supports maximization disabling only on Windows. If you want that on macOS or Linux you have to change the platform-specific files in the macos
or linux
folders. Note they are Swift and C++, not the Dart source files! But, platforms other than Windows are out of the scope of this article.
Integrating with System Clipboard
The calculator display isn’t a plain editable text field but a read-only text. Its business logic updates it in a customized way — + and – don’t appear, so the built-in system copy-paste features don’t work out of the box. The keystroke listener is already there, and only the business logic is missing. Now, add the ability to insert many digits at a time to the Calculator
class inside calculator.dart
file:
void replaceDigits(String? possibleDigits) {
print(possibleDigits);
if (possibleDigits != null && int.tryParse(possibleDigits) != null) {
_wasDigitJustAppended = true;
displayNotifier.value = possibleDigits;
}
}
If pasted data isn’t an integer, nothing happens. Next, fill the missing actions in CalculatorBody._onKey
inside calculator_body.dart
file:
} else if (event.isCopy()) {
Clipboard.setData(ClipboardData(text: _calculator.displayNotifier.value));
return KeyEventResult.handled;
} else if (event.isPaste()) {
Clipboard.getData(Clipboard.kTextPlain)
.then((data) => _calculator.replaceDigits(data?.text));
return KeyEventResult.handled;
}
Finally, press Alt+Enter to import the Clipboard
service. Note that class is already in the Flutter standard library. That’s because mobile platforms also have the clipboard. Keep in mind the getData method is asynchronous so you need to process the result in then
callback. You can’t use await
here because the onKey
method is synchronous.
Polishing the Project
The last part of the app is the AC button. Keystroke listener is already there. First, add an action to Calculator
inside calculator.dart
file:
void clear() {
_pendingOperation = null;
_operand = null;
_wasDigitJustAppended = false;
displayNotifier.value = '0';
}
Here we reset the state, the pending operation and digits to initial values. Next, bind the method in CalculatorBody._onKey
inside calculator_body.dart
file:
} else if (event.isClear()) {
_calculator.clear();
return KeyEventResult.handled;
} else if (event.character == '+') {
Finally, add the Tile
to the GridView
:
Tile('AC', (_) => _calculator.clear()),
That’s all. You have a working calculator desktop app written in Flutter! You can run the app using Shift+F10.
Where to Go From Here
You can download the complete starter and final projects using the Download Materials button at the top or bottom of this article.
If you want to work further on this project, you can add support for more desktop platforms (Linux and macOS). You can also extend the calculator business logic by adding more arithmetic operations or fractional numbers support.
For further reading about the Flutter Desktop, check these: